Каков формальный способ определения связи идентификатора _Thread_local?

Это вопрос типа «язык-юрист» по частному делу в Стандарте 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 здесь не актуальна.


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


Ответы (1)


Как я читал, согласно C11 6.2.4p4, в области видимости файла _Thread_local применяется к потоку main (), эффективно перемещая их как статические или внешние ссылки в блоке {} main (), а не auto, и оставил реализацию - определил, как функции потока, отличные от main (), имеют к ним доступ. Я согласен, что это дефект, заключающийся в том, что в нем не упоминается, что в определяющем объявлении любого объекта, который является _Thread_local, должно требоваться наличие static или extern в качестве дополнительного квалификатора, а не просто «может появиться» в качестве ссылочного объявления в 6.7.1p2. .

person M. Ziegast    schedule 27.02.2018
comment
Похоже, что все согласны с тем, что это дефект. Кто-то может возразить, что «спецификатор хранилища» - это слишком широкий класс, поскольку auto, extern и static используются по-разному: первый - указать продолжительность, второй - привязку, а третий - и то, и другое. Вопрос был о связке, поэтому 6.2.4 не очень актуален. Конечно, функции, отличные от main, могут обращаться к _Thread_local переменным, объявленным в области файла. - person alexsh; 01.03.2018