use*_*733 5 c arrays language-lawyer
以下代码可能存在未定义的行为:
uint64_t arr[1]; // Uninitialized
if(arr[0] == 0) {
Run Code Online (Sandbox Code Playgroud)
C标准指定具有自动存储持续时间的未初始化变量具有不确定的值,该值是未指定的或陷阱表示.它还指定uintN_t类型没有填充位,并且定义了值的大小和范围; 所以陷阱表示uint64_t是不可能的.
所以我得出结论,未初始化的值本身并不是未定义的行为.读它怎么样?
6.3.2.1左值,数组和函数指示符
- ...
除非它是运算
sizeof符的操作数,_Alignof运算符,一元&运算符,++运算符,--运算符或者左运算符.运算符或赋值运算符,没有数组类型的左值被转换为存储在指定对象中的值(并且不再是左值); 这称为左值转换....... 如果左值指定了一个自动存储持续时间的对象,该对象可以使用寄存器存储类声明(从未使用过其地址),并且该对象未初始化(未使用初始化程序声明并且未对其进行任何赋值)在使用之前),行为是未定义的.
- 除非它是sizeof运算符,_Alignof运算符或一元&运算符的操作数,或者是用于初始化数组的字符串文字,否则将具有类型''数组类型''的表达式转换为表达式输入''指向类型'的指针,指向数组对象的初始元素,而不是左值.如果数组对象具有寄存器存储类,则行为未定义.
问题:下标数组是否计为获取对象的地址?
下面的文字似乎暗示下标数组需要转换为指针,如果没有获取地址似乎无法做到:
6.5.2.1数组下标
约束
- 其中一个表达式应具有类型''指向完整对象类型'的指针,另一个表达式应具有整数类型,结果具有类型''type''.
语义
- 后缀表达式后跟方括号[]中的表达式是数组对象元素的下标名称.下标运算符[]的定义是E1 [E2]与(*((E1)+(E2)))相同.由于适用于binary +运算符的转换规则,如果E1是数组对象(等效地,指向数组对象的初始元素的指针)并且E2是整数,则E1 [E2]指定E2-元素E1(从零开始计数).
这使§6.3.2.1第3段看起来很奇怪.如果订阅需要转换为指针,那么数组怎么可以注册存储类呢?
是的,数组下标计为取地址,按照您在6.5.2.1中引用的部分.表达式E1必须具有其地址.
因此,6.3.2.1中UB的特殊情况不适用于数组索引.如果使用数组索引,则无论是否可以使用register存储持续时间存储该数组(具有其地址的变量不能使用register存储持续时间),则无关紧要.
您是正确的,假设读取stdint.h具有不确定值的未初始化类型(具有其地址)不会调用未定义的行为(由C11 7.20.1.1保证),但仅仅是未指定的行为.值可以是任何值,并且在几次读取之间可能是不确定的,但它不能是陷阱.
"读取一个未经传播的变量总是UB"是一个广泛但不正确的神话.有关此答案中规范性来源的进一步信息.
| 归档时间: |
|
| 查看次数: |
151 次 |
| 最近记录: |