Почему статическое выражение инициализации в C не может использовать элемент константного массива? - PullRequest
0 голосов
/ 27 июня 2018

Следующая (предположительно надуманная) программа на C не может быть скомпилирована:

int main() {
const int array[] = {1,2,3};
static int x = array[1];
}

При компиляции вышеуказанного исходного файла C с помощью gcc (или CL.EXE от Microsoft) я получаю следующую ошибку:

error: initializer element is not constant
static int x = array[1];
               ^

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

Кажется, что это может иметь какое-то отношение к тому, как компилятор генерирует код сборки для инициализации, потому что если вы удалите ключевое слово "static" (такое, что переменная "x" находится в стеке), то это компилируется нормально.

Однако еще одна странная вещь заключается в том, что он прекрасно компилируется в C ++ (даже с ключевым словом static), но не в C. Таким образом, компилятор C ++, похоже, способен генерировать необходимый код сборки для выполнения такой инициализации.

Edit: Благодарю Дэвислора - в попытке умиротворить власть имущих СО, я бы искал следующие типы фактической информации, чтобы ответить на вопрос:

  1. Существует ли какой-либо устаревший код, который поддерживал бы эту семантику, сломался бы?

  2. Были ли эти семантики официально предложены комитету по стандартам?

  3. Кто-нибудь когда-либо приводил причину отклонения допущения этой семантики?

Ответы [ 2 ]

0 голосов
/ 27 июня 2018

Если бы стандарт C допускал это, компиляторам пришлось бы знать, что находится в массивах. То есть компилятор должен иметь модель содержимого массива во время компиляции. Без этого компилятору предстоит выполнить небольшой объем работы для каждого массива: ему нужно знать его имя и тип (включая его размер), а также некоторые другие детали, такие как его связь и продолжительность хранения. Но если в коде указана инициализация массива, компилятор может просто записать соответствующую информацию в объектный файл, который он расширяет, а затем забыть об этом.

Если компилятор должен был иметь возможность извлекать значения из массива во время компиляции, он должен был бы запомнить эти данные. Поскольку массивы могут быть очень большими, это накладывает на компилятор C бремя, которого комитет, вероятно, не желал, поскольку C предназначен для работы в самых разных средах, в том числе с ограниченными ресурсами.

Комитет C ++ принял другое решение, и C ++ гораздо более обременителен для перевода.

0 голосов
/ 27 июня 2018

Объекты со статической продолжительностью хранения (читай: переменные, объявленные в области видимости файла или с ключевым словом static) должны быть инициализированы константами времени компиляции.

Раздел 6.7.9 стандарта C относительно состояний инициализации:

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

Раздел 6.6, касающийся состояний выражений констант:

7 Допускается больше широты для константных выражений в инициализаторах. Такая постоянная Выражение должно быть или оценивать одно из следующего:

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

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

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

Согласно приведенному выше определению, переменная const не квалифицируется как константное выражение, поэтому ее нельзя использовать для инициализации объекта static. С другой стороны, в C ++ обрабатывает const переменные как истинные константы и, таким образом, позволяет им инициализировать статические объекты.

...