我有以下示例
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
typedef struct test{
int a;
long b;
int c;
} test;
int main()
{
test *t = (test*) malloc(offsetof(test, c));
t -> b = 100;
}
它工作正常,但我不确定。我想我在这里有UB。我们有一个指向结构类型的对象的指针。但是结构类型的对象并不是真的有效。
我通过了标准,找不到此行为的任何定义。我可以找到的唯一与此部分接近的部分是6.5.3.2:
如果已将无效值分配给指针,则行为 一元*运算符未定义
但这并不重要,因为malloc
返回的指针是完全有效的。
标准中是否有解释这种行为的参考文献?我正在使用C11 N1570。
答案 0 :(得分:5)
存储在任何其他对象类型的非位字段对象中的值由n x CHAR_BIT位组成,其中n是该类型对象的大小(以字节为单位)。
因此,由于代码中分配的对象小于struct test
的大小,因此它不能包含该类型的对象的值。
现在考虑您的表情t -> b = 100
。 C2011, paragraph 6.5.2.3/4定义了->
运算符的行为:
后缀表达式,后跟
->
运算符和标识符指定结构或联合对象的成员。该值是第一个表达式指向的对象的命名成员 [...]的值。
(已添加重点。)我们已经确定您的t
并非(实际上,不能)指向struct test
,因此,我们可以说的最好大约6.5.2.3/4是它不适用于您的情况。 ->
运算符的行为没有其他定义,我们剩下paragraph 4/2(加了强调):
如果违反了在约束或运行时约束之外出现的“应”或“不应”要求,则该行为未定义。未定义的行为在本国际标准中通过“未定义的行为” 一词或通过省略行为的任何明确定义来表示。
就这样。您的代码的行为是不确定的。
答案 1 :(得分:-3)
因为malloc返回的指针是完全有效的。
没有指针不是“完全有效的”。完全没有。
您为什么认为指针“完全有效”?您没有分配足够的字节来容纳整个struct test
-指针不是“完全有效”的,因为没有有效的struct test
对象供您访问。
在C语言中没有像部分对象这样的东西。这就是为什么在C标准中找不到它的原因。
效果很好
不,不是。
“我没有观察到它爆炸。”与“效果很好”不同。
您的代码无法执行任何操作。对于the as-if rule,编译器可以自由执行整个操作,而仅从main()
返回零。