原始数据类型值超出范围的行为& C99的PRI *宏

时间:2010-03-13 01:14:59

标签: c

假设我们有一个8位无符号整数n(UINT8_MAX=255);编译器对n=256的行为是什么?当数据类型的值超出不同数据类型的范围时,我在哪里可以找到默认行为表?在超出范围时,它们的行为方式是否存在?

#include <stdio.h>
#include <inttypes.h>

uint8_t n = UINT8_MAX;
int main() {
  printf("%hhu ",n++);
  printf("%hhu",n);
  return 0;
}

使用gcc -std=c99 -Wall *.c进行编译,打印:255 0

另外,使用C99的PRI *宏是否可以接受?他们是如何命名的?

2 个答案:

答案 0 :(得分:5)

n=256;将带符号的整数值256转换为uint8_t,然后将其分配给n。此转换由标准定义,取值为模数256,因此结果是n设置为0

不确定在哪里可以找到表,但整数转换的规则是6.3.1.3:

  

1当整数类型的值为   转换为另一种整数类型   除了_Bool,如果值可以   由新类型代表,它是   不变。

     

2否则,如果新类型是   无符号,值由转换   反复添加或减去一个   超过可以达到的最大值   直到表示新类型   该值在新的范围内   type.49)

     

3否则,新类型已签名   并且该值无法表示   它;结果是   实现定义或   实现定义的信号是   升高

正如AndreyT指出的那样,这并未涵盖在计算过程中出现超出范围值时发生的情况,而不是转换期间发生的情况。对于6.2.5 / 9所涵盖的无符号类型:

  

涉及无符号的计算   操作数永远不会溢出,因为a   无法表示的结果   得到的无符号整数类型是   减少模数是一个数   大于最大值   可以用结果来表示   类型。

对于签名类型,3.4.3 / 3说:

  

示例未定义行为的示例是整数溢出的行为。

(间接,我知道,但是当这是未定义行为的规范示例时,我懒得继续搜索显式描述。)

另请注意,在C中,整数提升规则非常棘手。算术运算总是在相同类型的操作数上执行,因此如果表达式涉及不同的类型,则有一系列规则来决定如何选择要执行操作的类型。两个操作数都被提升为此常见类型。但是,它始终至少是一个int,因此对于像uint8_t这样的小类型,算术将在int中完成,并在分配给结果时转换回uint8_t。因此,例如:

uint8_t x = 100;
uint8_t y = 100;
unsigned int z = x * y;

结果是10000,而不是16,如果z也是uint8_t则会产生结果。

另外,使用C99的PRI *宏是否可以接受?他们是如何命名的?

可以接受谁?我不介意,但您可能想检查您的编译器是否支持它们。海湾合作委员会在我最早的版本中做了,3.4.4。它们在7.8.1中定义。

如果您没有C标准的副本,请使用:http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf。这是该标准的“草案”,在标准发布后的某个时间发布,包括一些更正。

答案 1 :(得分:2)

该行为在标准中有所描述。

(*)无符号整数类型实现模运算。模数等于2 ^ N,其中N是类型中的值形成位的数量。这意味着无符号类型在溢出(两端)上“环绕”。如果该类型的最大值为255,则256将在换行后变为下一个值,即0.

对于无符号类型,此行为的唯一例外是将浮点值转换为无符号类型。如果出现溢出,则行为未定义。

(*)签名整数类型不同。如果在浮点类型的转换期间发生溢出,则行为未定义(与无符号类型相同)。如果在转换期间从其他整数类型发生溢出,则结果是实现定义的。如果在算术运算期间发生溢出,则行为未定义。

(*)浮点类型在转换期间导致溢出时出现未定义的行为。