C 语言在编写代码时,定义常量是经常需要的,看例子:
#define BufferSize 256
可有时你看别人的代码时,会发现数字后面会加个后缀:
#define BufferSize 256U
为什么要加个后缀,今天我们就来把这个问题说明白。
一、 C 语言常量后缀有多少种
1 、 U : unsigned int
2 、 L : long
3 、 UL : unsigned long
4 、 LL : long long
5 、 ULL : unsigned long long
可以看出规律:
凡是带 U 的都是无符号,
凡是带 L 的都是 long 型,
所有的类型都是这几种的组合。
二、为什么加后缀,不加行不行
不加也可以,但有风险。
后缀的作用:字面常量的数据类型限定,防止溢出、隐式类型转换等 BUG 。
这种 BUG 一旦发生,很难定位。
三、 不加后缀,会有什么风险
1 、整型提升导致的比较陷阱
C 语言中,整型常量默认是 int 类型。如果你的常量超过了 int 的范围但未超过 unsigned int 的范围,编译器会自动把它当作 unsigned int 。这听起来很智能,但会埋下隐患。
看这段代码:
#define MAX_VAL 2147483648 // 大于 INT_MAX (2147483647)
long long val = -1;
if (val > MAX_VAL)
printf("val 更大 \n");
} else {
printf("MAX_VAL 更大 \n");
你的本意是想让 long long 类型的 -1 和这个大正数比较,结果应该是 "MAX_VAL 更大 " 对吧?可实际运行时,很可能会输出 "val 更大 " 。原因是 MAX_VAL 没有后缀,被默认为 unsigned int,而 -1 在与 unsigned int 比较时,会被隐式转换为一个巨大的无符号数( 0xFFFFFFFF ),结果自然就反了。
如果写成:
#define MAX_VAL 2147483648LL ,问题就迎刃而解。
2 、移位运算的溢出
位移操作对数据类型非常敏感:
#define BIT_MASK (1dy2