Почему C допускает оператор sizeof для переменной, которая еще не была создана? - PullRequest
0 голосов
/ 05 февраля 2020

Рассмотрим следующий пример кода:

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *a = malloc(sizeof *a);
    *a = 5;
    free(a);
    return 0;
}

В этом примере я выделяю целое число a в куче и инициализирую его равным 5. Эта строка специально

int *a = malloc(sizeof *a);

это то, что смущает меня (часть sizeof *a). Для меня это выглядит так, будто я пытаюсь получить размер переменной еще до того, как она будет создана, но я вижу, что этот стиль для инициализации указателей чрезвычайно распространен. Когда я компилирую этот код с помощью clang, я не получаю никаких ошибок или предупреждений. Почему компилятор позволяет это? Насколько я могу судить, это все равно что делать что-то вроде

int a = a + 1;

без какого-либо предыдущего объявления a. Это выдает предупреждение с clang -Wall main.c:

main.c:17:13: warning: variable 'a' is uninitialized when used
      within its own initialization [-Wuninitialized]
    int a = a + 1;

Чем эта строка отличается от объявления указателя с sizeof?

Ответы [ 2 ]

4 голосов
/ 05 февраля 2020

В большинстве случаев sizeof является оператором времени компиляции . Компилятор просто знает размер типа, который вы ему передаете.

Во-вторых, на самом деле в тот момент, когда malloc называется, переменная a фактически определена. Переменная должна быть определена (и размещена), прежде чем ее можно будет инициализировать. В противном случае, где будет записано значение инициализации?


Проблема с

int a = a + 1;

не в том, что a не существует, а в том, что значение a is неопределенный при использовании его в a + 1.

Для некоторых типов неопределенное значение может содержать представление ловушки , и если это приводит к неопределенному поведению .


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

3 голосов
/ 05 февраля 2020

Операнд оператора sizeof оценивается , а не , если только он не является массивом переменной длины. Он рассматривается только для определения его типа.

Это поведение описано в разделе 6.5.3.4p2 C стандарта :

The * Оператор 1011 * возвращает размер (в байтах) своего операнда, который может быть выражением или именем типа в скобках. Размер определяется по типу операнда. Результатом является целое число. Если тип операнда является типом массива переменной длины, операнд вычисляется; в противном случае, операнд не оценивается, а результатом является целочисленная константа.

В этом случае он знает, что *a имеет тип int, поэтому *a не оценивается и sizeof *a совпадает с sizeof(int).

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