Это вопрос типа «язык-юрист» по частному делу в Стандарте C11.
Правила, определяющие привязку идентификатора в программе на языке C, изложены в пункте 6.2.2 стандарта C11. В частности, 6.2.2 (5) утверждает, что (выделено мной):
Если объявление идентификатора для функции не имеет спецификатора класса хранения, его связь определяется точно так же, как если бы оно было объявлено с помощью спецификатора класса хранения
extern
. Если объявление идентификатора для объекта имеет область файла и не содержит спецификатора класса хранения, его связь является внешней.
В случае объявления, такого как _Thread_local int a;
в области файла, пункт 6.2.2 (5) выше не применяется, поскольку _Thread_local
является спецификатором хранилища. Ни одно из других положений 6.2.2 также не применяется (нет static
, поэтому (3) не применяется, не в области блока, является объектом, а не параметром, поэтому (6) не применяется и т. Д.). Так какой же должна связь a
быть в соответствии со Стандартом? Мне не хватает каких-то других правил, которые определяют связь в этом случае?
Я понимаю, что намерение состоит в том, чтобы иметь внешнюю связь (именно так gcc обрабатывает этот случай), но как это следует из самого Стандарта?
Обратите внимание, что совершенно нормально иметь объявление типа static _Thread_local int a; extern _Thread_local int a;
, и в этом случае применяются правила 6.2.2, и a
имеет внутреннюю связь (несмотря на extern
).
Наконец, семантика _Thread_local
здесь не актуальна.
extern
. Если объявление идентификатора для объекта имеет область видимости файла и не имеет спецификатора класса хранения, его связь является внешней. Это по сути то же самое, если не дословная копия. Я думаю, но не уверен, что этот параграф применяется, как если бы_Thread_local
не присутствовал. Возможно, можно было бы возразить, что здесь есть сбой, которого можно было бы избежать, если бы начать с нуля. - person Jonathan Leffler   schedule 28.01.2018register
объявления функций (которые, конечно, не имеют никакого смысла): нужно собрать 6.7.1 (7) (запрещает спецификаторы хранения, отличные отextern
для функций уровня блока) и 6.9 (2) (нет зарегистрироваться для объявлений области видимости файла), чтобы определить, что функции не могут быть объявленыregister
. Это работает, но я не уверен, что причина была такой запутанной. - person alexsh   schedule 28.01.2018extern
, либоstatic
. - person Jonathan Leffler   schedule 28.01.2018_Thread_local
- это первый спецификатор класса хранения, который не является взаимоисключающим со всеми остальными, и первый, который будет добавлен после C89; поэтому я согласен с Джонатаном Леффлером в том, что это редакционная ошибка - они пропустили взаимодействие с языком описания классов хранения. - person zwol   schedule 29.01.2018auto
иregister
: C11 §6.9 Внешние определения ¶2: Спецификаторы класса храненияauto
иregister
не должны появляться в спецификаторах объявления во внешнем объявлении. - person Jonathan Leffler   schedule 29.01.2018