Определение структуры в C с помощью Malloc - PullRequest
7 голосов
/ 01 февраля 2010

Ранее я задавал вопрос об определении структуры с помощью malloc. Это был ответ, который мне дал большинство:

struct retValue* st = malloc(sizeof(*st));

Я показывал другу мой код, и мы подошли к камню преткновения. Может кто-нибудь объяснить, почему этот код работает? С моей точки зрения, * st не был определен, когда вы его размещаете, так что там может быть любой мусор. Это должно быть malloc(sizeof(struct retValue))

Спасибо за любую помощь

Ответы [ 4 ]

19 голосов
/ 01 февраля 2010

Sizeof смотрит на тип выражения, данного ему, он не оценивает выражение. Таким образом, вам нужно только убедиться, что переменные, используемые в выражении, объявлены, чтобы компилятор мог определить их тип.

В вашем примере st уже объявлен как pointer-to-struct-retValue. Следовательно, компилятор может определить тип выражения "* st".

Хотя это не выглядит так, как будто оно уже объявлено в вашем коде, компилятор уже позаботился об этом за вас. Все объявления в вашем коде перемещаются в начало блока, в котором они встречаются компилятором. Предположим, вы пишете

Один из способов проиллюстрировать знания, доступные компилятору, - посмотреть промежуточный вывод, который он генерирует. Рассмотрим этот пример кода ...

struct retValue {long int a, long int b};
...
printf("Hello World!\n");
struct retValue* st = malloc(sizeof(*st));

Используя gcc в качестве примера и приведенный выше код в функции main () test.c , давайте посмотрим на промежуточный вывод, выполнив ...

gcc -fdump-tree-cfg test.c

Компилятор сгенерирует файл test.c.022t.cfg - Посмотрите на него, и вы увидите

[ ... removed internal stuff ...]
;; Function main (main)

Merging blocks 2 and 3
main (argc, argv)
{
  struct retValue * st;
  int D.3097;
  void * D.3096;

  # BLOCK 2
  # PRED: ENTRY (fallthru)
  __builtin_puts (&"Hello World!"[0]);
  D.3096 = malloc (16);
  st = (struct retValue *) D.3096;
  D.3097 = 0;
  return D.3097;
  # SUCC: EXIT

}

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

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

19 голосов
/ 01 февраля 2010

Оператор sizeof фактически не оценивает свой операнд - он просто смотрит на его типЭто делается во время компиляции, а не во время выполнения.Так что это можно безопасно выполнить до того, как переменная была назначена.

1 голос
/ 01 февраля 2010

Имеет значение объявление / определение типа структуры, а не определение объекта такого класса.Когда вы достигнете malloc, компилятор встретит объявление / определение, в противном случае вы получите ошибку компилятора.

Тот факт, что sizeof не оценивает свои операнды, являетсяпобочный вопрос.

Незначительный гад: помните, что нам нужны круглые скобки, когда мы вводим имена типов в sizeof как в:

sizeof(struct retValue);

, а не в случаеобъектов мы просто делаем:

sizeof *st;

См. стандарт:

6.5.3 Унарные операторы Синтаксис

unary-expression:
[...]
sizeof unary-expression
sizeof ( type-name )
0 голосов
/ 01 февраля 2010

В C sizeof является оператором и не оценивает его аргумент. Это может привести к «интересным» эффектам, которые новичок в C не обязательно предвидит. Я упомянул об этом более подробно в моем ответе на вопрос "Функция странного языка".

...