我想知道为什么在使用#define
预处理器时我们会演变常量?
例如:
#define WIDTH 128
它是否等于8位平台中的-128
?
如果我这样更改怎么办?
#define WIDTH 128U
在8位平台上它会等同于什么?
上面的常量整数的默认 sizeof 是什么?它的长度/类型取决于平台架构,还是取决于它们所包含的字面值的类型?
抱歉我的英语不好。
答案 0 :(得分:4)
将WIDTH
定义为128
不会产生任何问题,int
在所有符合要求的平台上至少为16位宽。
将WIDTH
定义为128U
会使其成为无符号整数常量文字。由于该值适合unsigned int
(强制要求至少16位宽),因此它具有类型unsigned int
。 sizeof(WIDTH)
评估为sizeof(unsigned int)
,这完全取决于平台。
使用此后缀不推荐。它会产生令人惊讶的副作用:
if (WIDTH > -1) {
printf("This will never print\n");
}
由于WIDTH
扩展为128U
unsigned
常量,因此比较将作为无符号比较执行,-1
将转换为unsigned
并变为{ {1}},一个远大于UINT_MAX
的值。不要这样做。
如果您随后将128
存储到WIDTH
变量中,则可能会出现问题。无论您将其定义为char
还是128
,实际上都没有区别,如果128U
类型为8位且已签名,您仍会有溢出,从而导致未定义的行为。在大多数平台上,存储的值确实是char
,但你甚至不能依赖它。
更重要的是,您应该通过启用所有编译器警告并使其出错来使用编译器可以提供的所有帮助:
-128
或
gcc -Wall -Wextra -Werror
这些警告很少令人讨厌,其中大部分非常有用,并指出了愚蠢的错误,错别字和疏忽。
答案 1 :(得分:2)
首先,{8}平台上的128
等于-128
。
其次,这与预处理器无关。预处理器的作用是将WIDTH
替换为它定义的任何内容。这就是您在源代码中撰写128
或128u
的原因。
后缀u
不是类型转换,而是指示文字的类型。在此示例中,128
是一个文字,其值为128 int
,而128u
是一个文字,其值为unsigned int
类型128。这里不是问题,但是如果你开始使用它们并且最终大于32767
,你可能会遇到问题。例如:
#define WIDTH 256u
#define HEIGHT 192u
unsigned npixels = WIDTH * HEIGHT;
应该注意的是,需要足够使其可移植(可能发生的情况是平台仅使用16位int
并且使用int,乘法会溢出,这意味着未定义的行为)。
另请注意,在较新的C标准(但不是古老的标准)中,如果可能的话,将扩展文字以尽可能大。例如,文字32768
表示带有值32768
的带符号整数类型,如果int
不足以容纳该有符号数,则会使用更大的类型。
sizeof
这些整数与sizeof(int)
相同,因为文字的类型为int
和unsigned int
。 sizeof(int)
的实际值可以是任何正整数。
答案 2 :(得分:1)
给C99章节,因为我手头没有C11文件。
ISO / IEC 9899:1999,6.4.4.1整数常量
整数常量的类型是相应列表中可以表示其值的第一个。
对于没有后缀的十进制常量:
int
long int
long long int
对于带u
或U
后缀的小数常量:
unsigned int
unsigned long int
unsigned long long int
ISO / IEC 9899:1999,5.2.4.2.1整数类型的大小
整数类型的宽度是实现定义的,二进制表示也是如此。
INT_MAX
- int
可以承担的最大值 - 保证 至少 +32767
。< / p>
UINT_MAX
- unsigned int
可以承担的最大值 - 保证 至少 65535
。< / p>
ISO / IEC 9899:1999,6.3.1.8通常的算术转换
如果您将int
与unsigned int
进行比较,int
将隐式转换为unsigned int
进行比较。类似于short
/ long
/ long long
类型。正如@chqrlie指出的那样,这可能是一个问题;如果发生这种情况,你的编译器应该给你一个警告( 总是在启用-Wall -Wextra
/ /W3
的情况下进行编译,不是吗?)。
<强>摘要强>
即使在8位计算机上,您的常量也会适合int
/ unsigned int
。假设它们不会,编译器会为它们使用下一个最大类型(而不是转换值)。
至于为什么我们这样做......
例如,如果您打算使用WIDTH
与sizeof()
的结果或strlen()
的返回代码或unsigned
的任何其他内容进行比较从本质上讲,您希望WIDTH
具有相同的值域,即能够保存所有可能的值。
这就是为什么你希望WIDTH
也是unsigned
。