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

Смешивание внешнего и const

Можно ли смешивать extern и const, как extern const? Если да, определяет ли классификатор константы его правило только в пределах области, в которой он был объявлен, или должен ли он точно соответствовать объявлению поступательного устройства, которое оно объявило? То есть могу ли я сказать extern const int i;, даже если фактический я не является константой и наоборот?

4b9b3361

Ответ 1

Обычный шаблон:

  • file.h:
    extern const int a_global_var;
  • file.c:
    #include "file.h"
    const int a_global_var =/* some const expression */;

Изменение: Объединенный комментарий legends2k. Благодарю.

Ответ 2

Вы можете использовать их вместе. Но вам нужно быть последовательным при использовании const, потому что, когда С++ называет декорирование, const включается в информацию о типе, которая используется для украшения имен символов. поэтому extern const int i будет ссылаться на другую переменную, чем extern int i

Если вы не используете extern "C" {}. C имя украшения не обращает внимание на const.

Ответ 3

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

Possibility.com достойная статья с дополнительным фоном.

Ответ 4

C++ 17 inline переменных

Если вы думаете, что хотите extern const, то более вероятно, что вы на самом деле захотите использовать встроенные переменные C++ 17.

Эта удивительная функция C++ 17 позволяет нам:

  • удобно использовать только один адрес памяти для каждой константы
  • сохранить его как constexpr: Как объявить constexpr extern?
  • сделать это в одной строке из одного заголовка

main.cpp

#include <cassert>

#include "notmain.hpp"

int main() {
    // Both files see the same memory address.
    assert(&notmain_i == notmain_func());
    assert(notmain_i == 42);
}

notmain.hpp

#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP

inline constexpr int notmain_i = 42;

const int* notmain_func();

#endif

notmain.cpp

#include "notmain.hpp"

const int* notmain_func() {
    return &notmain_i;
}

Скомпилируйте и запустите:

g++ -c -o notmain.o -std=c++17 -Wall -Wextra -pedantic notmain.cpp
g++ -c -o main.o -std=c++17 -Wall -Wextra -pedantic main.cpp
g++ -o main -std=c++17 -Wall -Wextra -pedantic main.o notmain.o
./main

GitHub вверх по течению.

Смотрите также: Как работают встроенные переменные?

C++ стандарт для встроенных переменных

Стандарт C++ гарантирует, что адреса будут одинаковыми. C++ 17 Типовой проект N4659 10.1.6 " Встроенный спецификатор":

6 Встроенная функция или переменная с внешней связью должны иметь одинаковый адрес во всех единицах перевода.

cppreference https://en.cppreference.com/w/cpp/language/inline объясняет, что если static не задан, то он имеет внешнюю связь.

Реализация встроенных переменных

Мы можем наблюдать, как это реализовано с:

nm main.o notmain.o

который содержит:

main.o:
                 U _GLOBAL_OFFSET_TABLE_
                 U _Z12notmain_funcv
0000000000000028 r _ZZ4mainE19__PRETTY_FUNCTION__
                 U __assert_fail
0000000000000000 T main
0000000000000000 u notmain_i

notmain.o:
0000000000000000 T _Z12notmain_funcv
0000000000000000 u notmain_i

и man nm говорит о u:

"U" Символ является уникальным глобальным символом. Это расширение GNU для стандартного набора привязок символов ELF. Для такого символа динамический компоновщик будет следить за тем, чтобы во всем процессе был только один символ с этим именем и типом.

Итак, мы видим, что для этого есть выделенное расширение ELF.

Пред- C++ 17: extern const

extern const работает как в примере ниже, но есть недостатки по сравнению с inline:

  • с помощью этой методики невозможно создать переменную constexpr, только inline позволяет: Как объявить constexpr extern?
  • это менее элегантно, так как вы должны объявить и определить переменную отдельно в заголовочном файле и файле cpp

main.cpp

#include <cassert>

#include "notmain.hpp"

int main() {
    // Both files see the same memory address.
    assert(&notmain_i == notmain_func());
    assert(notmain_i == 42);
}

notmain.cpp

#include "notmain.hpp"

const int notmain_i = 42;

const int* notmain_func() {
    return &notmain_i;
}

notmain.hpp

#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP

extern const int notmain_i;

const int* notmain_func();

#endif

GitHub вверх по течению.

Любой способ полностью встроить это?

TODO: есть ли способ полностью встроить переменную без использования памяти вообще?

Очень похоже на то, что делает препроцессор.

Это потребует как-то:

  • Запрещение или обнаружение, если адрес переменной взят
  • добавить эту информацию в объектные файлы ELF и позволить LTO оптимизировать ее

Связанные с:

Протестировано в Ubuntu 18.10, GCC 8.2.0.

Ответ 5

Да, вы можете использовать их вместе.

Если вы объявляете "extern const int i", то я является const во всей своей области. Невозможно переопределить его как неконстантный. Конечно, вы можете обойти флаг const, отбросив его (используя const_cast).