Выделение памяти для части структуры - PullRequest
0 голосов
/ 23 декабря 2018

У меня есть следующий пример

#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 голосов
/ 23 декабря 2018

С C2011, параграф 6.2.6.1/4:

Значения, хранящиеся в объектах без битового поля любого другого типа объекта, состоят из nx битов CHAR_BIT, где nэто размер объекта этого типа в байтах.

Следовательно, поскольку выделенный объект в вашем коде меньше размера struct test, он не может содержать значение объектаэтого типа.

Теперь рассмотрим ваше выражение t -> b = 100. C2011, пункт 6.5.2.3/4 определяет поведение оператора ->:

Выражение postfix, за которым следует оператор ->, а идентификатор обозначает членструктура или объект объединения.Это значение именованного члена объекта, на который указывает первое выражение [...].

(выделение добавлено). МыВы установили, что ваш t (на самом деле не может ), однако, указывает на struct test, поэтому лучшее, что мы можем сказать о 6.5.2.3/4, это то, что оно не относится к вашемудело.Поскольку нет никакого другого определения поведения оператора ->, у нас остается параграф 4/2 (выделение добавлено):

Если '' должен ''или «не должен» требование, которое появляется вне ограничения или ограничения времени выполнения, нарушено, поведение не определено.Неопределенное поведение иначе обозначено в этом международном стандарте словами «неопределенное поведение» или пропуском любого явного определения поведения .

Итак, вы здесь.Поведение вашего кода не определено.

0 голосов
/ 23 декабря 2018

, поскольку указатель, возвращаемый функцией malloc, полностью действителен.

Нет, указатель не является "полностью допустимым".Совсем нет.

Почему вы думаете, что указатель "полностью допустим"?Вы не выделили достаточно байтов для хранения всего struct test - указатель не является «полностью допустимым», так как нет действительного объекта struct test для доступа к нему.

Нет такой вещи какчастичный объект в C. Вот почему вы не можете найти его в стандарте C.

Он отлично работает

Нет, нет.

«Я не заметил, как он взорвался».это не то же самое, что «Он работает нормально».

Ваш код не делает ничего заметного.Согласно правилу «как будто» , компилятор может полностью исключить все это и просто вернуть ноль из main().

...