为何将size_t变量赋值给off_t会触发符号转换错误?
为什么
off_t off_1 = sz;触发符号转换错误而off_t off_2 = sizeof(long);不会? 环境信息
我使用的GCC版本如下:
$ gcc --version gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
问题代码
考虑以下使用-Werror=sign-conversion编译的简单代码片段:
#include <stddef.h> #include <sys/types.h> int main(void){ size_t sz = sizeof(long); off_t off_1 = sz; // 错误:从'size_t'(别名'long unsigned int')转换为'off_t'(别名'long int')可能改变结果符号 off_t off_2 = sizeof(long); // 编译正常 return 0; }
标准依据
根据N2596/6.5.3.4 sizeof和_Alignof运算符:
两个运算符的结果值由实现定义,其类型(无符号整数类型)为
size_t,定义于<stddef.h>(及其他头文件)。
问题分析
核心原因是GCC对编译期常量表达式和变量的转换检查逻辑不同:
- 对于
sizeof(long):它是编译期可确定的常量表达式,GCC能直接计算出具体数值(在你的系统中,这个值远小于off_t(long int)的正数最大值)。编译器可以明确判断该值转换为有符号类型不会出现符号变化,因此不会触发-Wsign-conversion警告(也就不会因为-Werror升级为错误)。 - 对于变量
sz:尽管它被初始化为sizeof(long),但默认优化级别下,GCC不会将其视为常量。此时编译器只能基于类型进行检查:size_t是无符号类型,off_t是有符号类型,理论上存在无符号值超出有符号类型取值范围的可能(比如size_t的最大值转换为long int会变成负数),因此编译器会触发符号转换错误。
简单来说,编译器对常量可以做精准的数值范围校验,对变量只能做类型层面的安全预判。
内容的提问来源于stack exchange,提问作者Some Name
相关产品推荐
相关产品推荐

