C语言赋值时转更长数据类型的行为及高位填充问题
C语言类型转换相关问题解答
嘿,这两个问题都是C语言类型转换里的基础但关键的点,我来给你掰扯清楚~
问题1:窄类型转宽类型的赋值行为
当你把一个长度更短的数据类型转换为更长的类型时,行为完全取决于原类型是有符号还是无符号:
- 如果原类型是有符号类型(比如
int、short、time_t这类常见的带符号整数):会执行符号扩展——把原类型的最高位(也就是符号位)复制到新类型的所有高位字节中。这么做的目的是保证转换后的值和原数值的正负性一致,不会出现正数变负数或者负数变正数的情况。 - 如果原类型是无符号类型(比如
unsigned int、unsigned short):会执行零扩展——直接把新类型的所有高位字节都填充为0。因为无符号类型没有负数值,只需要保证转换后的数值大小和原数值完全一致就行。
问题2:4字节tv_sec转8字节long long的填充情况
先明确前提:gettimeofday里的tv.tv_sec一般是time_t类型,在绝大多数32位/64位系统中,它都是4字节的有符号整数。那把它转换为8字节的long long时,就会触发上面说的符号扩展:
- 正常情况下,
tv_sec是正数(毕竟时间戳从1970年1月1日开始都是正的),它的最高位是0,所以转换后long long变量t的高4字节会全部被填充为0,最终t的值就是tv_sec * 1000的正确结果。 - 极端场景下(比如系统时间被设置为1970年之前),
tv_sec会是负数,此时它的最高位是1,那么t的高4字节就会全部填充为1,这样转换后的long long值依然是原负数的正确扩展,不会出现数值失真。
再看你给出的代码示例:
{ long long t; gettimeofday(&tv,NULL); t = (long long)(tv.tv_sec) * 1000 ; // Some Operation }
这里先把tv.tv_sec强制转换为long long再做乘法,是非常稳妥的写法!如果不做这个强制转换,tv.tv_sec * 1000会先以4字节的time_t类型计算,一旦结果超过4字节有符号整数的最大值(2147483647),就会发生溢出,再转成long long也没法恢复正确值了。先转成long long再计算,整个乘法过程是在8字节的范围内进行的,能完美避免溢出问题。
内容的提问来源于stack exchange,提问作者DSR
相关产品推荐
相关产品推荐

