Является ли константное представление переменной четко определенным?

Если у вас есть переменная, которая на самом деле является константой после того, как она была установлена ​​в коде инициализации, можно ли объявить ее 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++.

Краткое описание дубликата: он вызывает неопределенное поведение и, следовательно, недействителен.

wohlstad 20.04.2024 13:38
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
1
84
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я думаю, это правильно: можно объявить переменную как 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 в качестве оптимизации.

njlarsson 20.04.2024 12:23

Код ОП неверен, даже если вы найдете реализацию, которая его принимает (что, я вполне верю, возможно). «Это работает в реализации X» или даже «… в большинстве реализаций» — это совсем не то же самое, что «у него четко определенное поведение». Посмотрите цель обмана и/или другой ответ.

John Bollinger 20.04.2024 14:10

Кроме того, «сбоев я не заметил» — это не то же самое, что «всегда будет работать». Если вы наблюдаете за оживленным шоссе в течение 20 секунд и не видите никаких аварий, вы не можете заключить, что никто никогда не погибнет в автокатастрофе - однако это та же самая логика, которую вы применили здесь.

Andrew Henle 20.04.2024 14:19
Ответ принят как подходящий

Является ли константное представление переменной четко определенным?

Нет.

Если у вас есть переменная, которая на самом деле является константой после того, как она была установлена ​​в коде инициализации, можно ли объявить ее 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:

Поведение не определено в следующих случаях:

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

Другие вопросы по теме