为一部分结构分配内存

时间:2018-12-23 14:56:06

标签: c struct language-lawyer undefined-behavior

我有以下示例

#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。

2 个答案:

答案 0 :(得分:5)

来自C2011, paragraph 6.2.6.1/4

  

存储在任何其他对象类型的非位字段对象中的值由n x CHAR_BIT位组成,其中n是该类型对象的大小(以字节为单位)。

因此,由于代码中分配的对象小于struct test的大小,因此它不能包含该类型的对象的值。

现在考虑您的表情t -> b = 100C2011, 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()返回零。