Я разрабатываю микро-фреймворк для модульного тестирования и хочу, чтобы у клиента была возможность определить «имя набора тестов». Итак, у меня есть следующий заголовочный файл с именем test_suite.h
:
static const char *const test_suite_name;
static inline void run_all_tests(void){
printf("Running ");
if(!test_suite_name){
printf("unnamed suite");
} else {
printf("%s suite", test_suite_name);
}
//run tests
}
Цель этого состоит в том, чтобы позволить клиентам "переопределить" test_suite_name
следующим образом:
#include "test_suite.h"
extern const char *const test_suite_name = "suite1";
Я думаю, поведение такого использования четко определено , поскольку static const char *const test_suite_name;
представляет собой предварительное определение, а затем extern const char *const test_suite_name = "suite1";
представляет собой внешнее определение. Нет разногласий по поводу связи с 6.2.2(p4)
:
Для идентификатора, объявленного со спецификатором класса хранения extern
в
область, в которой видна предыдущая декларация этого идентификатора, 31) если
предыдущая декларация определяет внутреннюю или внешнюю связь,
связь идентификатора при последующем объявлении
такая же, как у связи, указанной в предыдущем объявлении.
Я провел несколько экспериментов:
- https://coliru.stacked -crooked.com
Распечатывает следующее сообщение об ошибке:
error: redefinition of 'const char* const suite_name'
extern const char *const suite_name = "some suite";
DEMO
- https://ideone.com/:
Работает совершенно нормально, без предупреждений
DEMO
gcc7.4.0
на моей машине.
Выдает предупреждение:
warning: ‘test_suite_name’ initialized and declared ‘extern’
Вопрос: Является ли поведение кода, показанного выше, хорошо определенным?
Я почти уверен, что поведение будет неопределенным, если написать следующее:
#include "test_suite.h"
const char *const test_suite_name = "suite1"; //without extern
из-за 6.2.2(p5)
(подчеркните мой):
Если объявление идентификатора для функции не имеет
спецификатор класса хранилища, его связь определяется точно так же, как если бы
он был объявлен со спецификатором класса хранения extern
. Если
объявление идентификатора для объекта имеет область видимости файла и не имеет
спецификатор класса хранилища, его связь внешняя.
Таким образом, у нас было бы несоответствие между static const char *const test_suite_name;
с внутренней связью и const char *const test_suite_name = "suite1";
с внешней связью.