Если у вас есть переменная, которая на самом деле является константой после того, как она была установлена в коде инициализации, можно ли объявить ее const
в заголовочном файле? Например:
extdef.h:
#ifndef DEFINING_X
extern const int x;
#endif
void init_x();
extdef.c:
#define DEFINING_X
#include "xdef.h"
int x;
void init_x() { x = 42; }
основной.с:
#include <stdio.h>
#include "xdef.h"
int main(int argc, char *argv[]) {
init_x();
printf("x is %d\n", x);
}
Очевидно, что это не совсем безопасно, поскольку он требует вызова init_x
перед обращением к x
, но если я гарантирую это, могу ли я верить, что это четко определено? Когда я тестирую, кажется, что он работает ожидаемым образом.
Обратите внимание, что я использую только простой C, а не C++.
Я думаю, это правильно: можно объявить переменную как const в заголовочном файле, если она на самом деле является константой после установки в коде инициализации. Ваш код вполне корректен.
Вы можете проверить это:
#include <stdio.h>
#include "xdef.h"
int main(int argc, char *argv[]) {
printf("x is %d before calling init_x()\n", x);
init_x();
printf("x is %d after calling init_x()\n", x);
return 0;
}
Выход:
x is 0 before calling init_x()
x is 42 after calling init_x()
Спасибо, но ваш ответ не несет никакой новой информации. Мне нужно знать, четко ли это определено, например, что значение x не извлекается предварительно до или во время вызова init_x в качестве оптимизации.
Код ОП неверен, даже если вы найдете реализацию, которая его принимает (что, я вполне верю, возможно). «Это работает в реализации X» или даже «… в большинстве реализаций» — это совсем не то же самое, что «у него четко определенное поведение». Посмотрите цель обмана и/или другой ответ.
Кроме того, «сбоев я не заметил» — это не то же самое, что «всегда будет работать». Если вы наблюдаете за оживленным шоссе в течение 20 секунд и не видите никаких аварий, вы не можете заключить, что никто никогда не погибнет в автокатастрофе - однако это та же самая логика, которую вы применили здесь.
Является ли константное представление переменной четко определенным?
Нет.
Если у вас есть переменная, которая на самом деле является константой после того, как она была установлена в коде инициализации, можно ли объявить ее const в заголовочном файле?
Нет.
Могу ли я поверить, что это четко определено?
Нет.
Из https://port70.net/~nsz/c/c11/n1570.html#6.2.7p2:
Все объявления, ссылающиеся на один и тот же объект или функцию, должны иметь совместимый тип; в противном случае поведение не определено.
Оба extern const int x;
и int x;
относятся к одному и тому же объекту.
Из https://port70.net/~nsz/c/c11/n1570.html#6.2.7p1:
Два типа имеют совместимый тип, если их типы одинаковы. Дополнительные правила определения совместимости двух типов описаны [...] в 6.7.3 для квалификаторов типа [...]
Из https://port70.net/~nsz/c/c11/n1570.html#6.7.3p10:
Чтобы два квалифицированных типа были совместимы, оба должны иметь идентичную квалифицированную версию совместимого типа [...]
Типы const int x
и int x
несовместимы, поскольку имеют разную квалификацию. Правила нарушены, поведение кода неопределенное. Вы можете прочитать о неопределенном поведении на странице Неопределённое, неопределённое и определяемое реализацией поведение.
Это также упоминается в https://port70.net/~nsz/c/c11/n1570.html#J.2:
Поведение не определено в следующих случаях:
- Два объявления одного и того же объекта или функции указывают типы, которые несовместимы.
Краткое описание дубликата: он вызывает неопределенное поведение и, следовательно, недействителен.