В библиотеке языка C , которую я написал, я обнаружил, что большинство операций слишком многословны, поэтому я попытался сделать ее краткой - с помощью макросов и зарезервировав идентификатор _
.
Насколько я понимаю, идентификаторы, начинающиеся с _
, зарезервированы для стандарта C, реализации и библиотек; но один только _
не упоминается. Я здраво предполагаю, что его может использовать программа (т. е. приложение).
Эта практика не нова, $_
довольно часто используется в Perl и содержит множество идиом. В Python и некоторых языках оболочки/скриптов _
также относится к значению последнего выражения.
Конечно, я не буду напрямую сталкиваться со скриптовыми языками. На что следует обратить внимание при использовании лексически-локального идентификатора _
в C? и в некоторых других языках системного программирования (например, Rust, C++)? Какие проблемы совместимости могут возникнуть из-за этого?
_
допустимо в C на уровне блока. _
также является официальным идентификатором заполнителя (который можно переопределить, а не просто переобъявить) в C++26 (комментарий к C++, поскольку в тексте вопроса упоминается «например, Rust, C++»)
«но только _ не упоминается» Если единственным символом является подчеркивание, это также первый символ. Это означает, что одиночное подчеркивание — это идентификатор, начинающийся с подчеркивания. И как таковое оно должно быть зарезервировано.
Я просмотрел заголовки вашей библиотеки и считаю, что ваша попытка сделать краткие версии функций и типов — плохая идея. Он фрагментирует API без какой-либо практической пользы, особенно если учесть, что исходные имена и так очень короткие.
@user694733 user694733 Самый большой мотив для меня сделать первый аргумент неявным - это добиться некоторого синтаксического сахара, такого как «развертка цепочки», такого как те, которые можно найти в официальном руководстве по Rust, без явного this
(например, stdin.readline().split("\t").sort()
). Не могли бы вы проиллюстрировать, почему это плохая идея и как она «фрагментирует» API? Я сделал «s2i.h» дополнительным заголовком в экспериментальной ветке специально для того, чтобы узнать об этом больше.
Как я уже упоминал выше, он фрагментирует ваш API: существует несколько способов сделать одно и то же. Вы также, по сути, изобретаете свой собственный синтаксис на основе препроцессора, который не могут понять никакие инструменты. C лучше всего, когда он пишется как C; не тогда, когда вы пытаетесь перевести это на другой язык. Не расстраивайтесь: все программисты на C в какой-то момент своей карьеры попадали в эту яму. По крайней мере, вы не пытались написать реализацию vtable с препроцессором, чтобы обеспечить полиморфизм классов в C.
@user694733 user694733 Я создал обсуждение, чтобы избавить комментарий от ненужных вещей. Я приглашаю модераторов провести рефакторинг этого раздела комментариев.
Вы уверены, что ваша библиотека была «слишком многословной»? Можете ли вы проиллюстрировать, что вы имеете в виду. Вездесущий соло _
в заголовке, обозначенный «краткой» ссылкой в вопросе, вызывает недоумение. Если имена ваших функций были очень длинными (более 32 символов, что означает ограничение из воздуха), тогда да: использовать такие имена громоздко. Но повышение краткости, вероятно, будет достигнуто за счет использования подходящих, последовательных и недвусмысленных сокращений слов в именах функций. В стандарте C есть strcpy()
, а не unchecked_string_copy()
(который состоит всего из 21 символа) — вы можете/должны сделать то же самое.
@JonathanLeffler Ну, Vulkan и OpenGL гораздо более многословны, чем моя библиотека, и это половина причины, которая меня убедит. Однако моя библиотека бесполезна, если я не смогу сделать то, что она делает, легко. Отсюда и пост в связанном обсуждении
Стандарт 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 Точно так же следует избегать использования одной цифры l
(строчная L) по тем же причинам, поскольку во многих шрифтах она выглядит как 1
(один).
Re: «Однако присвоение имени макросу _
будет проблемой, поскольку это помещает _
в обычное пространство имен в области файла»: Имена макросов не находятся в обычном пространстве имен и не находятся в области файла. Что касается области видимости, то области действия файла, функции, прототипа функции и блока являются понятиями только на этапе 7 трансляции программы, то есть компиляции, которая концептуально происходит после предварительной обработки. Имена макросов обрабатываются на этапе 4. Что касается пространства имен, в C 2018 6.10.3 сказано: «… Существует одно пространство имен для имен макросов…»
@EricPostpischil Ну, это упрощенное объяснение. Если есть макрос, то он, очевидно, начнет расширять другие варианты использования этого имени макроса, что приведет к различным странным проблемам компиляции.
Помимо вопросов о том, зарезервирован ли _
для реализации C, он не зарезервирован для вашей библиотеки. Программа, использующая вашу библиотеку, может определить ее для своих собственных целей: либо макросы, либо идентификаторы с областью действия параметров блока, функции или функции, либо имена членов структур или объединений, и они могут конфликтовать с заголовками вашей библиотеки. Сюда входят и другие сторонние библиотеки, которые применяют ту же стратегию, что и ваша, и определяют _
для своих целей — если клиентская программа попытается включить как вашу библиотеку, так и другую, возникнет конфликт.
Конфликтов между сторонними библиотеками и их клиентами обычно можно избежать, выбрав какой-то отличительный префикс и используя его для каждого идентификатора, определенного в библиотеке, который может быть виден клиенту.
Имена идентификаторов не сохраняются при компиляции, поэтому я не понимаю, какой тип взаимодействия между ними и другими языками вы имеете в виду.