C: как работает оператор точка / стрелка под капотом? - PullRequest
2 голосов
/ 18 июня 2019

Из того, что я понимаю, дано

int *x = malloc(10 * sizeof(int));
x[5] = 13;

malloc просто выделяет пустое пространство (без предположения об объекте, который будет туда помещен), а x[5] переводится в *(x + 5), который рассматривается как целое число. Таким образом, оператору [] остается создать иллюзию массива.

Но что происходит в следующем случае?

struct test {
    int a;
    char b;
};

struct test* x = malloc(sizeof(struct test));
x->a = 3;
x->b = 'a';

Переводит ли x->a, x->b в какую-либо позицию памяти обычным образом, как это делает оператор [i]? Ссылка C указывает что-нибудь, или это специфическая реализация? Я просматривал различные книги, но, в отличие от массивов, структуры всегда представлены в виде черного ящика.

Ответы [ 2 ]

2 голосов
/ 18 июня 2019

Скажем, int - это 4 байта, а char - 1 байт (я не знаю эти цифры наизусть, но допустим, что это правильно). Тогда структура test будет 5 последовательных байтов в памяти (сначала a (4 байта), а затем b (1 байт)).

Если вы затем позвоните test->b, то вы указываете на начало этого struct плюс смещение в 4 байта. (поскольку test является указателем, ->a означает средство +0 и ->b означает средство +4)

1 голос
/ 18 июня 2019

malloc просто выделяет пустое пространство (без предположения об объекте, который будет туда помещен)

Правильно.Динамически выделяемая память, в частности, не имеет типа до того момента, когда вы что-то напишите в эту область.Формально язык C называет это эффективным типом .Формальное определение находится в C17 6.5 / 7:

эффективный тип объекта для доступа к его сохраненному значению является объявленным типом объекта, если таковой имеется.Если значение сохраняется в объекте, у которого нет объявленного типа, через lvalue, имеющий тип, который не является символьным типом, то тип lvalue становится эффективным типом объекта для этого доступа и для последующих доступов, которые не изменяютсохраненное значение.

То, что возвращается из malloc, - это просто необработанный кусок памяти, без специальных атрибутов, до точки, где вы пишете в эту область.После чего компилятор должен нанести на него «метку типа».Как только вы получите к нему доступ с помощью [], компилятор должен будет предположить, что выделенные данные должны рассматриваться как массив, чтобы система типов оставалась согласованной между статически размещенными и динамически размещаемыми объектами.

Аналогичнообласть памяти становится структурой в точке, когда вы обращаетесь к памяти, так как она будет иметь отступы и т. д. и будет определять смещение памяти каждого элемента.Поэтому, если дана структура с противоположным порядком вашего примера, например:

struct test {
    char a;
    int  b;
};

Тогда это определяется реализацией, если x->b приведет к доступу к байту 1, байту 4 или чему-то еще, так каккомпилятор может свободно добавлять отступы между членами.

Но как только вы получите доступ к x->something, компилятору придется начать с любых 1026 * точек в качестве эффективного типа struct test или системы типов.не будет вести себя последовательно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...