Распределение памяти после объявления переменной класса extern - PullRequest
0 голосов
/ 11 февраля 2019

В нескольких местах я читал, что при объявлении внешней переменной память не назначается до тех пор, пока не будет сделано определение.Я пытался этот код, который дает противоречивый вывод в GCC.

#include <stdio.h>

int main() {
    extern int a;
    printf("%lu", sizeof(a));
    return 0;
}

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

aditya@theMonster:~$ ./a
4

Ответы [ 4 ]

0 голосов
/ 11 февраля 2019

В вашем коде действительно есть проблема, но не там, где вы ожидаете:

  • передача значения типа size_t для printf спецификации преобразования %ld имеет неопределенное поведение, если size_t и unsigned long имеют разные размеры или представления, как это имеет место во многих системах (16-разрядные системы, Windows 64-разрядные ...).

Вот исправленная версия, переносимаядля систем, не соответствующих C99, чья библиотека C printf может не поддерживать %zu:

#include <stdio.h>

int main(void) {
    extern int a;
    printf("%lu\n", (unsigned long)sizeof(a));
    return 0;
}

Относительно того, почему программа компилируется и выполняется без ошибок:

  • Переменнаяa объявлено внутри тела main со связью extern: для него не выделено места, и a будет неопределенным вне тела main.
  • sizeof(a) оцениваетсяво время компиляции в качестве константы sizeof(int), которая на вашей платформе равна 4.
  • Компилятор не генерирует дальнейших ссылок на a, поэтому компоновщик не жалуется на a нигде не определен.
0 голосов
/ 11 февраля 2019

Размер переменной - это размер ее типа данных, независимо от того, является ли он в настоящее время только extern или нет.Поскольку sizeof вычисляется во время компиляции, тогда как разрешение символов выполняется во время компоновки, это приемлемо.

Даже с -O0, gcc не важно, что это extern;он помещает 4 в esi для аргумента printf: https://godbolt.org/z/Zv2VYd

Без объявления a, однако, произойдет сбой любого из следующих действий:

a = 3;
printf("%d\n", a);
int *p = &a;
0 голосов
/ 11 февраля 2019

a является целым числом, поэтому его размер равен 4.

Его местоположение (адрес) и значение в настоящее время неизвестны.
(где-то в другом месте extern)

Но размер четко определен.

0 голосов
/ 11 февраля 2019

Вы можете сойти с рук здесь, потому что a фактически никогда не используется.Выражение sizeof(a) вычисляется во время компиляции.Так как на a никогда не ссылаются, компоновщик не ищет его.

Если бы вы сделали это вместо этого:

printf("%d\n", a);

Тогда программа не смогла бы связать, печатая"неопределенная ссылка на` а '"

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