Запрос на внимание при использовании '_' <подчеркивания> в качестве идентификатора в C (и взаимодействия с другими языками)

В библиотеке языка C , которую я написал, я обнаружил, что большинство операций слишком многословны, поэтому я попытался сделать ее краткой - с помощью макросов и зарезервировав идентификатор _.

Насколько я понимаю, идентификаторы, начинающиеся с _, зарезервированы для стандарта C, реализации и библиотек; но один только _ не упоминается. Я здраво предполагаю, что его может использовать программа (т. е. приложение).

Эта практика не нова, $_ довольно часто используется в Perl и содержит множество идиом. В Python и некоторых языках оболочки/скриптов _ также относится к значению последнего выражения.

Конечно, я не буду напрямую сталкиваться со скриптовыми языками. На что следует обратить внимание при использовании лексически-локального идентификатора _ в C? и в некоторых других языках системного программирования (например, Rust, C++)? Какие проблемы совместимости могут возникнуть из-за этого?

Имена идентификаторов не сохраняются при компиляции, поэтому я не понимаю, какой тип взаимодействия между ними и другими языками вы имеете в виду.

Ulrich Eckhardt 27.06.2024 09:39
_ допустимо в C на уровне блока. _ также является официальным идентификатором заполнителя (который можно переопределить, а не просто переобъявить) в C++26 (комментарий к C++, поскольку в тексте вопроса упоминается «например, Rust, C++»)
Weijun Zhou 27.06.2024 09:39

«но только _ не упоминается» Если единственным символом является подчеркивание, это также первый символ. Это означает, что одиночное подчеркивание — это идентификатор, начинающийся с подчеркивания. И как таковое оно должно быть зарезервировано.

Gerhardh 27.06.2024 09:40

Я просмотрел заголовки вашей библиотеки и считаю, что ваша попытка сделать краткие версии функций и типов — плохая идея. Он фрагментирует API без какой-либо практической пользы, особенно если учесть, что исходные имена и так очень короткие.

user694733 27.06.2024 11:07

@user694733 user694733 Самый большой мотив для меня сделать первый аргумент неявным - это добиться некоторого синтаксического сахара, такого как «развертка цепочки», такого как те, которые можно найти в официальном руководстве по Rust, без явного this (например, stdin.readline().split("\t").sort()). Не могли бы вы проиллюстрировать, почему это плохая идея и как она «фрагментирует» API? Я сделал «s2i.h» дополнительным заголовком в экспериментальной ветке специально для того, чтобы узнать об этом больше.

DannyNiu 27.06.2024 12:59

Как я уже упоминал выше, он фрагментирует ваш API: существует несколько способов сделать одно и то же. Вы также, по сути, изобретаете свой собственный синтаксис на основе препроцессора, который не могут понять никакие инструменты. C лучше всего, когда он пишется как C; не тогда, когда вы пытаетесь перевести это на другой язык. Не расстраивайтесь: все программисты на C в какой-то момент своей карьеры попадали в эту яму. По крайней мере, вы не пытались написать реализацию vtable с препроцессором, чтобы обеспечить полиморфизм классов в C.

user694733 27.06.2024 13:12

@user694733 user694733 Я создал обсуждение, чтобы избавить комментарий от ненужных вещей. Я приглашаю модераторов провести рефакторинг этого раздела комментариев.

DannyNiu 27.06.2024 13:58

Вы уверены, что ваша библиотека была «слишком многословной»? Можете ли вы проиллюстрировать, что вы имеете в виду. Вездесущий соло _ в заголовке, обозначенный «краткой» ссылкой в ​​вопросе, вызывает недоумение. Если имена ваших функций были очень длинными (более 32 символов, что означает ограничение из воздуха), тогда да: использовать такие имена громоздко. Но повышение краткости, вероятно, будет достигнуто за счет использования подходящих, последовательных и недвусмысленных сокращений слов в именах функций. В стандарте C есть strcpy(), а не unchecked_string_copy() (который состоит всего из 21 символа) — вы можете/должны сделать то же самое.

Jonathan Leffler 27.06.2024 16:51

@JonathanLeffler Ну, Vulkan и OpenGL гораздо более многословны, чем моя библиотека, и это половина причины, которая меня убедит. Однако моя библиотека бесполезна, если я не смогу сделать то, что она делает, легко. Отсюда и пост в связанном обсуждении

DannyNiu 28.06.2024 08:19
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
98
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Стандарт C конкретно говорит о C17 7.1.3:

  • Все идентификаторы, начинающиеся с подчеркивания, заглавной буквы или другого подчеркивания, всегда зарезервированы для любого использования, за исключением тех идентификаторов, которые лексически идентичны ключевым словам.
  • Все идентификаторы, начинающиеся с подчеркивания, всегда зарезервированы для использования в качестве идентификаторов с областью действия файла как в обычном пространстве имен, так и в пространстве имен тегов.

На простом английском языке это означает, что:

  • Идентификаторы, начинающиеся с __ или _A (любая заглавная буква), зарезервированы для компилятора и стандартной библиотеки компилятора (подробности здесь: Что означает «зарезервировано для любого использования»?). Поэтому, если вы используете такие идентификаторы, вы можете столкнуться с конфликтами имен со стандартной библиотекой.
  • Любой идентификатор, начинающийся с _, зарезервирован для использования при объявлении чего-либо вне функции (в том числе при объявлении функции). «Пространства имен тегов» относятся к тегам struct/union/enum, объявленным вне функции.

Это означает, что вам не следует писать такой код, как:

// BAD
int _;
void f (void); // this function here to illustrate that _ is at file scope

или

// BAD
void _ (void);

или

// BAD
struct _ {/* ... */};
void f (void);  // this function here to illustrate that _ is at file scope

или вы можете столкнуться с конфликтами имен. Однако вы можете написать код типа

// OK
void f (void)
{
  int _ = something;
}

или

// OK
#define x(_) _

int main() {
  int _ = x(5);
  printf("%d",_);
}

Параметр макроса не является идентификатором области файла, а расширяется и разрешается внутри main(). Однако присвоение имени макросу _ будет проблемой, поскольку при этом _ помещается в обычное пространство имен в области файла (идентификаторы имен макросов всегда видны в области файла).


При этом называть переменную _ для каких-либо целей — ужасная идея. Если какой-то код кажется вам слишком многословным, то наверняка вы сможете хотя бы придумать трехбуквенный идентификатор, который будет гораздо более информативным? val, cnt, fun, adr, tmp и т. д.

Я когда-либо видел идентификатор _, используемый только в контексте игры в код, запутывания кода или «презентации» своих знаний бессмысленных экзотических функций C. Итак, если вы действительно подумываете об использовании _, знайте, что вы попадаете в одну из этих категорий. И это не лестно для кода — быть зарезанным на следующем код-ревью.

Я согласен с выводом. Использование одиночного подчеркивания является антишаблоном, поскольку это один из наименее видимых символов в наборе символов. Особенно при использовании его рядом с другими маленькими символами, так как это превращает код в суп из символов, который трудно читать.

user694733 27.06.2024 11:16

@ user694733 Точно так же следует избегать использования одной цифры l (строчная L) по тем же причинам, поскольку во многих шрифтах она выглядит как 1 (один).

Lundin 27.06.2024 11:18

Re: «Однако присвоение имени макросу _ будет проблемой, поскольку это помещает _ в обычное пространство имен в области файла»: Имена макросов не находятся в обычном пространстве имен и не находятся в области файла. Что касается области видимости, то области действия файла, функции, прототипа функции и блока являются понятиями только на этапе 7 трансляции программы, то есть компиляции, которая концептуально происходит после предварительной обработки. Имена макросов обрабатываются на этапе 4. Что касается пространства имен, в C 2018 6.10.3 сказано: «… Существует одно пространство имен для имен макросов…»

Eric Postpischil 27.06.2024 13:46

@EricPostpischil Ну, это упрощенное объяснение. Если есть макрос, то он, очевидно, начнет расширять другие варианты использования этого имени макроса, что приведет к различным странным проблемам компиляции.

Lundin 27.06.2024 14:04

Помимо вопросов о том, зарезервирован ли _ для реализации C, он не зарезервирован для вашей библиотеки. Программа, использующая вашу библиотеку, может определить ее для своих собственных целей: либо макросы, либо идентификаторы с областью действия параметров блока, функции или функции, либо имена членов структур или объединений, и они могут конфликтовать с заголовками вашей библиотеки. Сюда входят и другие сторонние библиотеки, которые применяют ту же стратегию, что и ваша, и определяют _ для своих целей — если клиентская программа попытается включить как вашу библиотеку, так и другую, возникнет конфликт.

Конфликтов между сторонними библиотеками и их клиентами обычно можно избежать, выбрав какой-то отличительный префикс и используя его для каждого идентификатора, определенного в библиотеке, который может быть виден клиенту.

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