简体   繁体   English

为什么我们施展不变的文字

[英]Why do we cast constant literals

I am wondering why do we cast constants when using #define preprocessor? 我想知道为什么在使用#define预处理器时我们会抛出常量?

For example: 例如:

#define WIDTH 128

Would it be equal to -128 in an 8bit platform? 在8位平台上它会等于-128吗?

What if I change it like this: 如果我改变它会怎么样:

#define WIDTH 128U

What would it be equal to, on 8bit platform? 在8位平台上它会等同于什么?

What is the default sizeof a constant integers like the above? 像上面这样的常量整数的默认大小是多少? Do its length/type depends on the platform architecture, or it depends on the type of the literal value they hold? 它的长度/类型取决于平台架构,还是取决于它们所包含的字面值的类型?

Sorry about my bad English. 抱歉我的英语不好。

Defining WIDTH as 128 poses no problems, int is at least 16 bit wide on all conforming platforms. WIDTH定义为128不会产生任何问题, int在所有符合要求的平台上至少为16位宽。

Defining WIDTH as 128U would make it an unsigned integer constant literal. WIDTH定义为128U将使其成为无符号整数常量文字。 Since the value fits in an unsigned int (mandated to be at least 16 bit wide), it has type unsigned int . 由于该值适合unsigned int (强制为至少16位宽),因此它具有unsigned int类型。 sizeof(WIDTH) evaluates to sizeof(unsigned int) , which is entirely platform specific. sizeof(WIDTH)计算为sizeof(unsigned int) ,它完全是特定于平台的。

Using this suffix is not recommended . 建议不要使用此后缀。 It would have surprising side effects: 它会产生令人惊讶的副作用:

 if (WIDTH > -1) {
    printf("This will never print\n");
 }

Since WIDTH expands to 128U , an unsigned constant, the comparison is performed as an unsigned comparison, -1 is converted to unsigned and becomes UINT_MAX , a value much larger than 128 . 由于WIDTH扩展为128Uunsigned常量),因此比较作为无符号比较执行, -1转换为unsigned并变为UINT_MAX ,这个值远大于128 Don't do this. 不要这样做。

If you subsequently store WIDTH into a char variable, you may have a problem. 如果随后将WIDTH存储到char变量中,则可能存在问题。 It would actually not make a difference whether you define it as 128 or 128U , you would still have an overflow if the char type is 8 bit and signed, leading to undefined behavior. 无论您将其定义为128还是128U ,实际上都没有区别,如果char类型为8位且签名,您仍会有溢出,从而导致未定义的行为。 On most platforms, the value stored would indeed be -128 but you cannot even rely on that. 在大多数平台上,存储的值确实是-128但你甚至不能依赖它。

More importantly, you should use all the help the compiler can give you by enabling all compiler warnings and making them errors: 更重要的是,您应该通过启用所有编译器警告并使其出错来使用编译器可以提供的所有帮助:

gcc -Wall -Wextra -Werror

or 要么

clang -Weverything -Werror

Very few of these warnings are annoying, most of them are very useful and point to silly mistakes, typos and oversights. 这些警告很少令人讨厌,其中大部分非常有用,并指出了愚蠢的错误,错别字和疏忽。

First of all 128 is not equal to -128 on a 8-bit platform. 首先,在8位平台上128 等于-128

Second this has nothing to do with the preprocessor. 其次,这与预处理器无关。 What the preprocessor does is to replace WIDTH with whatever it's defined as. 预处理器的作用是将WIDTH替换为它定义的任何内容。 That is the question is why you write 128 or 128u in your source. 这就是为什么你在源代码中写128128u的原因。

The suffix u is not about type casting, it's about to indicate the type of the literal. 后缀u不是类型转换,它将指示文字的类型。 In this example 128 is an literal with value 128 of type int while 128u is a literal with value 128 of type unsigned int . 在此示例中, 128是一个文字,其值为128,类型为int128u是一个文字,其值为128,类型为unsigned int It's not a problem immediately here, but if you start to use them and end up larger than 32767 you could run into problems. 这里不是问题,但如果你开始使用它们并最终大于32767你可能会遇到问题。 For example: 例如:

#define WIDTH   256u
#define HEIGHT  192u

unsigned npixels = WIDTH * HEIGHT;

it should be noted that the suffices are required to make it portable (what could happen is that the platform only uses 16-bit int s and with int the multiplication would overflow which means undefined behavior). 应该注意的是,需要足够使其可移植(可能发生的情况是平台仅使用16位int并且使用int,乘法将溢出,这意味着未定义的行为)。

Also note that in newer C standards (but not the antique ones) will extend the literal to become as large as necessary if possible. 另请注意,在较新的C标准(但不是古老的标准)中,如果可能的话,将扩展文字以尽可能大。 For example the literal 32768 means a signed integral type with value 32768 , if int isn't large enough to hold that signed number then larger types would be used. 例如,文字32768表示带有值32768有符号整数类型,如果int不足以容纳该有符号数,则将使用更大的类型。

The sizeof these integers are the same as sizeof(int) as the type of the literals are int and unsigned int . 这些整数的sizeofsizeof(int)相同,因为文字的类型是intunsigned int The actual value of sizeof(int) could be any positive integer. sizeof(int)的实际值可以是任何正整数。

Giving C99 chapters because I don't have the C11 document at hand. 给C99章节因为我手头没有C11文件。


ISO/IEC 9899:1999, 6.4.4.1 Integer constants ISO / IEC 9899:1999,6.4.4.1整数常数

The type of an integer constant is the first of the corresponding list in which its value can be represented. 整数常量的类型是相应列表中可以表示其值的第一个。

For decimal constants without suffix: 对于没有后缀的十进制常量:

  • int
  • long int
  • long long int

For decimal constants with u or U suffix: 对于带有uU后缀的十进制常量:

  • unsigned int
  • unsigned long int
  • unsigned long long int

ISO/IEC 9899:1999, 5.2.4.2.1 Sizes of integer types ISO / IEC 9899:1999,5.2.4.2.1整数类型的大小

The width of integer types is implementation-defined, as is the binary representation. 整数类型的宽度是实现定义的,二进制表示也是如此。

INT_MAX -- the largest value an int can take -- is guaranteed to be at least +32767 . INT_MAX - int可以采用的最大值 - 保证 至少为 +32767

UINT_MAX -- the largest value an unsigned int can take -- is guaranteed to be at least 65535 . UINT_MAX - unsigned int可以采用的unsigned int - 保证 至少为 65535


ISO/IEC 9899:1999, 6.3.1.8 Usual arithmetic conversions ISO / IEC 9899:1999,6.3.1.8通常的算术转换

If you compare an int with an unsigned int , the int will be implicitly converted to unsigned int for the comparison. 如果 intunsigned int 进行比较 ,则int将被隐式转换为unsigned int以进行比较。 Similar for the short / long / long long types. 类似于short / long / long long类型。 As @chqrlie pointed out, this can be a problem; 正如@chqrlie指出的那样,这可能是一个问题; your compiler should give you a warning if this happens (you are always compiling with -Wall -Wextra / /W3 enabled, aren't you?). 你的编译器应该给你一个警告,如果发生这种情况( 总是编译-Wall -Wextra / /W3启用,不是吗?)。


Summary 摘要

Your constants will fit into an int / unsigned int even on an 8-bit machine. 即使在8位机器上,你的常量也适合int / unsigned int Assuming they would not, the compiler would use the next largest type for them (instead of casting the value). 假设它们不会,编译器将使用它们的下一个最大类型(而不是转换值)。

As for why we do it... 至于为什么我们这样做......

If you, for example, intend to use WIDTH for comparisons with the result of sizeof() , or the return code of strlen() , or anything else that is unsigned by nature, you would want WIDTH to have the same value domain, ie being able to hold all possible values. 例如,如果您打算使用WIDTHsizeof()的结果或strlen()的返回代码或其他任何本质上unsigned的内容进行比较,您可能希望WIDTH具有相同的值域,即能够掌握所有可能的价值观。

That is why you would want WIDTH to be unsigned as well. 这就是为什么你希望WIDTH也是unsigned

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM