c - 扩展标准C中的移位或算术运算

标签 c c99 c11

对不起,英语不好。

uint16_t a, c;
uint8_t b = 0xff;

a = b<<8;
c = b*10;


我们得到的ac的值是多少?任意整数类型的情况如何?

最佳答案

uint16_t a, c;
uint8_t b = 0xff;

a = b<<8;


首先,对<<的参数执行整数提升。常量8int,因此不会转换。由于uint8_t的转换等级小于int的转换等级,并且uint8_t的所有值都可以表示为int,因此b会被转换-保留其值-变为int。然后将得到的int值向左移八位。

如果int仅16位宽,则值0xff * 2^8不能表示为int,然后该移位调用未定义的行为-n1570和C99中的6.5.7(4):


  如果E1具有带符号的类型和非负值,并且E1×2E2可表示为结果类型,则为结果值;否则,行为是不确定的。


否则,结果为255*256 = 65280 = 0xFF00。由于该值可以用a类型表示,因此将int转换结果转换为uint16_t会保留该值。如果结果超出范围(例如,移位距离为9 [并且int足够宽]),则将对2^16取模,以得到02^16 - 1范围内的值, >。

c = b*10;


通常的算术转换是对uint16_t的操作数执行的。两个操作数都具有整数类型,因此首先执行整数提升。由于*10,并且int类型的所有值都可以表示为b,因此整数提升使两个操作数具有相同的类型int,并且通常的算术转换不需要任何进一步的转换。乘法是在类型int处完成的,其结果int再次可以用2550类型表示,因此在将值存储在c中之前进行的对uint16_t的转换将保留该值。


  任意整数类型的情况如何?


对于c


整数促销;转换级别小于或等于<<(和int)[宽度为unsigned int <=的整数类型]和位域为(unsigned) int的整数类型的值/表达式, _Boolintsigned int转换为unsigned intint(如果unsigned int可以表示原始类型的所有值,则为int,否则为unsigned int)。
如果(提升的)右操作数(移位距离)为负或大于或等于(提升的)左操作数的宽度(值位的数量加符号位;有一个符号位或没有符号位),则行为是未定义。如果(提升的)左操作数的值为负,则行为未定义。如果(提升的)左操作数的类型是无符号的,则结果为value * 2^distance,以模2^width为模。如果(提升的)左操作数的类型是带符号的且值是非负的,则结果为value * 2^distance(如果该类型可以表示该类型),否则行为未定义。
如果在2中未发生未定义的行为,则结果将转换为存储在其中的变量的类型。


如果目标类型为_Bool(或其别名),则将非零结果转换为1,将零结果转换为0,否则
如果结果可以目标类型表示,则保留其值,否则
如果目标类型是无符号的,则结果以模2^width的形式减少,否则
结果以实现定义的方式转换,或者引发实现定义的信号。



对于*


执行通常的算术转换,以便两个(转换后的)操作数具有相同的类型。
以结果类型执行乘法;如果那是有符号整数类型并且乘法溢出,则该行为是不确定的。
以与上述相同的方式将结果转换为目标类型。




这就是定义抽象机的方式,如果实现可以通过另一种方式达到相同的结果(定义了行为),则它可以在按条件规则下随意执行。

关于c - 扩展标准C中的移位或算术运算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13785955/

相关文章:

c - 如何为 C11 U“unicode 文字”正确使用 `__attribute__((format (printf, x, y)))`?

c - SIGIO 只通知线程池中的最后一个线程

c++ - "&a+1 > &a"会导致未定义的行为吗

c - 堆栈链表,带功能的遍历器链表

c - 使用宏在运行时堆栈中优雅地创建可变大小的“2D指针”列表

c - 释放全局变量

C11 - 编译器忽略潜在的无限循环

c - 是使用任何未定义的不确定值还是仅使用存储在具有自动存储的对象中的值?

ios - 如何在 iOS 应用程序中使用 c 静态库?

c - 向二叉搜索树添加节点随机删除节点