在Linux上使用gcc版本4.8.4,short是16位,int是32位.
#include "stdio.h"
int main( void ){
unsigned short u = 0xaabb;
unsigned int v = 0xaabb;
printf ("%08x %08x\n", u, (unsigned short)((u*0x10001)/0x100));
printf ("%08x %08x\n", v, (unsigned short)((v*0x10001)/0x100));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
结果:
0000aabb 0000bbab
0000aabb 0000bbaa
Run Code Online (Sandbox Code Playgroud)
这可以改变,例如,通过除以0x10,其为第一种情况产生类似的结果(+1).如果截断的字节/0x100
小于0x80 ,则不会发生这种效应.第一种情况(short u
)的机器代码看起来好像是要进行一些舍入(添加0xFF).
Lun*_*din 14
类似的文字0x10001
将是类型int
(如果它可以适合int,在这种情况下是正确的).int
是签名类型.
由于变量u
是一个小整数类型,因此int
无论何时在表达式中使用,它都会被提升为整数.
0xaabb * 0x10001
应该会给出结果0xAABBAABB
.但是,这个结果太大了,无法容纳在int
32位二进制补码系统中,其中a的最大数字int
是0x7FFFFFFF
.所以你得到一个有符号整数的溢出,因此调用未定义的行为 - 任何事情都可能发生.
在进行任何形式的二进制算术时,切勿使用有符号整数!
此外,最终的强制转换(unsigned short)
是徒劳的,因为printf参数int
无论如何都会提升传递的值.严格说来也是不正确的,因为预期的%x
意思printf
是unsigned int
.
为了避免C中不可预测和有限的默认整数类型的所有问题,请stdint.h
改为使用.此外,使用unsigned int literals解决了许多隐式类型提升错误.
例:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main( void ){
uint16_t u = 0xaabb;
uint16_t v = 0xaabb;
printf ("%08" PRIx16 " %08" PRIx16 "\n", u, (uint16_t)(u*0x10001u/0x100u));
printf ("%08" PRIx16 " %08" PRIx16 "\n", v, (uint16_t)(v*0x10001u/0x100u));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
(此代码也将具有参数提升,但是通过使用PRIx16
格式说明符,您可以告诉printf
现在编译器的业务是使代码工作,而不管函数调用中可能存在哪种类型的促销.)