C11标准下含不完全类型结构体的暂定定义是否属未定义行为?
该C代码在C11标准下的行为分析
先看你给出的代码:
static struct S a; int main() { return (long)&a; } struct S { int b; } s;
我们分两部分来拆解这段代码的合规性,判断是否属于未定义行为(UB):
一、文件作用域static struct S a;与后续结构体定义的合法性
你提到了C11标准6.9.2条款关于暂定定义的规则:
在文件作用域中声明对象标识符时,若未指定初始化器,且未指定存储类说明符或指定static存储类说明符,则构成暂定定义(tentative definition)
这里需要关注暂定定义与不完整类型的交互逻辑,6.9.2条款第2段补充了关键说明:
如果一个暂定定义的标识符的类型是不完整类型,那么该暂定定义不会被视为一个定义,直到该类型被完成为止。如果在翻译单元结束时,该类型仍然不完整,那么行为是未定义的。
在你的代码中,static struct S a;声明时struct S确实是不完整类型,但后续的struct S { int b; } s;语句完成了struct S的类型定义(同时定义了对象s)。按照C11标准的规则,当结构体类型完成定义后,前面的暂定定义static struct S a;会被自动视为带有零初始化的文件作用域静态对象定义,这部分完全符合标准,不属于未定义行为。
二、return (long)&a;的行为分析
这段代码的另一个核心点是将对象指针转换为long类型并返回,C11标准6.3.2.3第5段对此有明确规定:
一个指针可以转换为一个整数类型。转换的结果是实现定义的。如果转换不能用整数类型表示,行为是未定义的。结果不必是可移植的。
简单来说:
- 如果目标平台上
long类型的宽度足以容纳指针的值(比如32位系统中long和指针都是32位),这个转换的结果是实现定义的(具体值由编译器决定),但不属于未定义行为; - 如果
long的宽度小于指针的宽度(比如64位系统中long是32位、指针是64位),转换无法完整容纳指针值,此时属于未定义行为。
总结
回到你的问题:依据C11标准,这段代码是否属于未定义行为?
- 结构体声明与暂定定义的部分完全合法,不存在未定义行为;
- 指针转
long的部分是否属于未定义行为,取决于目标平台的long类型宽度是否能容纳指针值,并非在所有场景下都是UB。
内容的提问来源于stack exchange,提问作者Shivam Sarodia
相关产品推荐
相关产品推荐

