意外的宏计算

Unexpected macro evaluation

本文关键字:计算 意外      更新时间:2023-10-16

为什么这是ffffffff ?

#define MYMACRO(n) (((uint16_t)0 - 1) >> (16 - (n)))
std::cout << std::hex << MYMACRO(1);

同时打印1 ?

#define MYMACRO(n) (((uint32_t)0 - 1) >> (32 - (n)))
std::cout << std::hex << MYMACRO(1);

我用GCC和cpp.sh试过了

说明在type-promotion-in-c.

(§6.3.1.1布尔值、字符和整数):

如果int型可以表示原类型的所有值,则将该值转换为int型;…这些被称为整数提升。所有其他类型都不受整数提升的影响。

因此,对于第一种情况,((uint16_t)0 - 1)被转换为int以满足减法的需要。因此右移操作是算术右移,而不是逻辑右移。

c++中有积分提升。尽管如此,实际测试表达式并不是一个坏主意,以了解幕后发生了什么…

#include <typeinfo>
#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
int main(){
#define MYMACRO(n) (((uint16_t)0 - 1) >> (16 - (n)))
    std::cout << std::hex << MYMACRO(1);
    std::cout << "n-----n";
#undef MYMACRO
#define MYMACRO(n) (((uint32_t)0 - 1) >> (32 - (n)))
    std::cout << std::hex << MYMACRO(1);
    std::cout << "n--++++--n";
    std::cout << boost::typeindex::type_id<decltype((uint16_t)0)>().pretty_name() << std::endl;
    std::cout << boost::typeindex::type_id<decltype((uint16_t)0 - 1)>().pretty_name() << std::endl;    
    std::cout << boost::typeindex::type_id<decltype((uint32_t)0 - 1)>().pretty_name() << std::endl;
}

移位运算符后的整数类型在本例中不相关。从上面程序的输出中可以看到Live On Coliru

ffffffff
-----
1
--++++--
unsigned short
int
unsigned int

总结:

  • 子表达式:(uint16_t)0产生unsigned short,在大多数平台上通常

  • 表达式:(uint16_t)0 - 1产生int类型;因为整数提升规则。1是类型为int的整型常数

  • 表达式:(uint32_t)0 - 1)产生unsigned int类型;仍然是因为通常的算术转换unsigned int被认为大于int