Почему эта статическая const char * специфична для архитектуры инициализации? - PullRequest
1 голос
/ 22 октября 2019

Этот вопрос относится к Почему постоянная инициализация необходима для статического символа *, а не для статического символа **

Ответ на отмеченный вопрос научил меня, что static const char* инициализация должна бытьадрес, разрешаемый во время компиляции. В том же ответе указывалось, что указатель должен быть const, а не (обязательно) содержимым, на которое указывал указатель. Это отражено в приведенном ниже коде.

Почему тогда следующий код цели зависит от архитектуры? (т.е. почему этот код генерирует ошибку компилятора с некоторыми, но не со всемикомпиляторы?)

// main.c

static const char* const text = "foo";
static const char* tmp = text;

int main( int argc, char* argv[] ) { return 0; }

Успешная компиляция:

$ /path/to/tgt1-linux-gnu-gcc --version && /path/to/tgt1-linux-gnu-gcc ./main.c && echo $?
tgt1-linux-gnu-gcc (crosstool-NG 1.23.0.485-ee829 - next) 8.2.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

0

Неудачная компиляция:

$ /path/to/tgt2-linux-gnueabi-gcc --version && /path/to/tgt2-linux-gnueabi-gcc ./main.c
tgt2-linux-gnueabi-gcc (crosstool-NG 1.18.0) 4.7.3 20130102 (prerelease)
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

./main.c:4:1: error: initializer element is not constant

Ответы [ 2 ]

3 голосов
/ 22 октября 2019

Это не зависит от архитектуры. Версии вашего компилятора отличаются, наряду с доступными оптимизациями.

Примечание:

8.2.0

против

4.7.3 20130102 (prerelease)

Возможно, вы можете обойти это (не проверено) наtgt2 GCC путем компиляции с -O2.

2 голосов
/ 22 октября 2019

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

Как уже заметил @ JL2210, вы фактически используете дваразные компиляторы, хотя оба являются версиями GCC. Эти конкретные версии по умолчанию соответствуют совершенно другим языковым стандартам - GCC 4 по умолчанию - C89, тогда как GCC 8 по умолчанию - C2011 - но это не проблема. Все версии стандарта C имеют очень похожие формулировки в соответствующих областях, и незначительные различия не меняют способ их применения к вашему коду.

Что касается инициализаторов, C89 содержит следующие языковые ограничения:

Все выражения в инициализаторе для объекта со статической длительностью хранения [...] должны быть константными выражениями.

, тогда как аналогичное ограничение в C11 равно

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

Прежде чем вы взволнованы по поводу добавления "строковых литералов" вC11, отмечу, что рассматриваемое выражение инициализации text однозначно не строковый литерал, несмотря на то, что соответствующая переменная сама инициализируется. Таким образом, вопрос сводится к тому, является ли это «постоянным выражением». Однако, независимо от всех const -членов в своем типе, это не так.

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

В C89 это соответствующее определение:

Константа адреса - это указатель назначение, обозначающее объект статической длительности хранения или обозначение функции; он должен быть создан явно, с использованием унарного оператора &, или неявно, с помощью выражения массива или типа функции . Массив-индекс [] и членский доступ. и -> операторы, унарные операторы адреса и косвенности * и приведение указателей могут использоваться при создании константы адреса, но значение объекта не должно быть доступно с помощью этих операторов.

C11 выражает это следующим образом:

Константа адреса - это нулевой указатель, указатель на значение l, обозначающее объект статической длительности хранения, или указатель на указатель функции; оно должно быть создано явно с использованием унарного оператора & или целочисленной константы, приведенной к типу указателя, или неявно с помощью выражения массива или типа функции . Массив-индекс [] и членский доступ. и -> операторы, унарные операторы адреса & и косвенного обращения * и приведение указателей могут использоваться при создании адресной константы, но значение объекта не должно быть доступно при использовании этих операторов.

(Выделение добавлено в обоих случаях.)

Выражение text не является явным выражением в унарном операторе &. Это не целочисленная константа, приведенная к типу указателя. Это не выражение типа массива (ни типа функции).

В любом случае, ваш код не только не соответствует, но и нарушает языковые ограничения. Поэтому соответствующий компилятор обязан выдавать диагностику. GCC не обязан отклонять код, но это одна из подходящих альтернатив. В этих условиях вполне разумно, чтобы версия 8 понимала, что инициализатор действительно является константой, хотя технически не является константным выражением. Однако для того, чтобы он действительно соответствовал требованию диагностики, вам, возможно, потребуется указать опцию -pedantic. Выполнение всей такой необходимой диагностики является как раз целью этой опции.

...