Подтвердить что ты не робот

Несколько массивов длиной 0 строк имеют одинаковый адрес?

Следующий код печатает один и тот же адрес для a и b с использованием GCC (не протестирован с другими компиляторами):

#include <stdio.h>

void show() {
    {
        static char a[0];
        printf("%p\n", a);
    }
    {
        static char b[0];
        printf("%p\n", b);
    }
}

int main() {
    show();
}

Мой вопрос в том, что C-стандарт позволяет нескольким переменным иметь один и тот же адрес, или это просто расширение GCC?

4b9b3361

Ответ 1

В параграфе C11 6.7.6.2p1 говорится:

Ограничения

  • В дополнение к необязательным типам классификаторов и ключевому слову static, [ и ] могут ограничивать выражение или *. Если они ограничивают выражение (которое задает размер массива), выражение должно иметь целочисленный тип. Если выражение является константным выражением, оно должно иметь значение больше нуля.

Поскольку ваша программа нарушает должна (0 не больше нуля), программа будет иметь поведение undefined, за исключением того, что в этом случае она появляется в пределах ограничений. Как говорится в разделе 4 Соответствие

4 Соответствие

  • В настоящем международном стандарте "должен" должен быть интерпретирован как требование для реализации или в программе; наоборот, "не должно" интерпретироваться как запрет.

  • Если требование '' should '' или 'не должно' ', которое появляется за пределами ограничения или ограничения времени выполнения, нарушается, поведение undefined. Поведение undefined иначе указано в этом Международном стандарте словами "поведение undefined" или отсутствием какого-либо явного определения поведения. В этих трех различиях нет разницы; все они описывают поведение "undefined".

Кроме того, 5.1.1.3p1 говорит:

  • Соответствующая реализация должна содержать как минимум одно диагностическое сообщение (идентифицированное определенным образом), если блок перевода для предварительной обработки или блок перевода содержит нарушение любого синтаксиса правило или , даже если поведение также явно указано как undefined или определено для реализации. Диагностические сообщения не должны возникать при других обстоятельствах. [9])

С примечанием к сноске:

9) Цель состоит в том, чтобы реализация должна определять характер и, по возможности, локализовать каждое нарушение. Разумеется, реализация может свободно производить любое количество диагностических операций, пока действительная программа все еще правильно переводится. Он также может успешно преобразовать недопустимую программу.


Таким образом,

  • C11 не имеет массивов размера 0.

  • Наличие таких массивов является нарушением ограничения

  • Однако GCC позволяет массивы нулевого размера в качестве расширения

  • Соответствующая реализация C должна создавать диагностическое сообщение при таком использовании.

  • Этот GCC компилирует этот с настройками по умолчанию без вывода диагностического сообщения даже после установки -std=c11 делает gcc -std=c11 несоответствующей реализацией.

  • Документация GCC гласит, что:

    [...], чтобы получить всю диагностику, требуемую стандартом, вы также должны указать -pedantic (или -pedantic-errors, если вы хотите, чтобы они были ошибками, а не предупреждениями).

  • Таким образом, чтобы использовать GCC для компиляции таким образом, чтобы он соответствовал стандарту C11, вы должны явно использовать не менее gcc -std=c11 -pedantic; и вы получите:

    zerosizearray.c:5:21: warning: ISO C forbids zero-size array ‘a’ [-Wpedantic]
           static char a[0];
    
  • Однако GCC по-прежнему будет компилировать вашу программу, даже если это некорректная программа (если вы не используете -pedantic-errors); в этом случае, естественно, не будет применяться ни один из требований стандарта.

Так как стандарт C фактически не разрешает объекты с нулевым размером (если я правильно прочитал, определение структуры должно также иметь по крайней мере один элемент и т.д.), и это больше того, что разные объекты должны занимать различное пространство в память, из которой происходят разные адреса для объектов; в стандарте ничего не указывается об адресах объектов размером 0.

Ответ 2

В стандартном C массив с нулевым размером не разрешен.

Если вы скомпилируете его с помощью опции -pedantic, используя gcc. Это даст предупреждение, сказав:

zero.c: 3: 6: предупреждение: ISO C запрещает массив нулевого размера 'a' [- > pedantic]

Ответ 3

Как уже было сказано, 0 массивов длины не допускаются в стандартном компиляторе C и GCC, разрешая его как расширение. Я хотел бы добавить еще одну вещь: поведение вашей программы, которую вы поставили под вопрос, undefined. Вы должны использовать void* при использовании спецификатора формата% p, потому что спецификатор формата printf %p ожидает аргумент типа void*.

Смотрите этот ответ: printf и указатели

Ответ 4

что массивы нулевой длины являются gcc-расширением и не поддерживаются стандартной библиотекой, поведение зависит от реализации расширения gcc

вы можете увидеть документы GCC здесь

6.17 Массивы нулевого нуля

a zero length array известен как flexible array

  • Элементы гибкого массива записываются как содержимое [] без 0.
  • Элементы гибкого массива имеют неполный тип, поэтому оператор sizeof не может быть применен. Как quirk исходной реализации массивов нулевой длины, sizeof оценивает до нуля.
  • Элементы гибкого массива могут отображаться только как последний элемент структуры, который в противном случае не является пустым.
  • Структура, содержащая элемент гибкого массива, или объединение, содержащее такую ​​структуру (возможно, рекурсивно), не может быть членом структуры или элемента массива. (Тем не менее, эти использования разрешены GCC в качестве расширений.)