Які найпоширеніші угоди про іменування в C?


126

Які умови іменування зазвичай використовуються в C? Я знаю, що принаймні два:

  1. GNU / linux / K&R з функціями нижнього_чатка
  2. ? ім'я? з функціями UpperCaseFoo

Я говорю про С тільки тут. Більшість наших проектів - це невеликі вбудовані системи, в яких ми використовуємо C.

Ось який я планую використовувати для свого наступного проекту:


C Конвенція про найменування

Struct              TitleCase
Struct Members      lower_case or lowerCase

Enum                ETitleCase
Enum Members        ALL_CAPS or lowerCase

Public functions    pfx_TitleCase (pfx = two or three letter module prefix)
Private functions   TitleCase
Trivial variables   i,x,n,f etc...
Local variables     lower_case or lowerCase
Global variables    g_lowerCase or g_lower_case (searchable by g_ prefix)

7
Я б не застосовував префікс 'g_' на глобальних змінних; Я б застосував значущі імена (так client_locale, а не cl_lc як глобальне ім'я змінної). Classic C не використовує футляр для верблюдів; Я написав код у футлярі на C, і він виглядає дивно (тому більше не роблю цього). Однак це не є помилковим - і послідовність важливіша за те, яка конвенція використовується. Уникайте typedefs, які інкапсулюють структурні покажчики; вважаємо стандарт C - "FILE *" написано таким чином, а не FILE_PTR.
Джонатан Леффлер

2
@ Джонатан Леффлер, що не так з g_ для позначення глобальних? У вбудованих системах у мене виникли проблеми, коли важко було відстежувати міжмодульні залежності через глобальні зміни та зовнішній g_somevar. Я особисто вважаю, що це взагалі погана ідея, але подібні речі зазвичай робляться з міркувань продуктивності. Наприклад, глобальний прапор, який встановлюється переривкою, що вказує на готовність даних.
JeffV

2
Для того, що варто, ця конвенція іменування здебільшого була зірвана з конвенцій PalmOS API. Крім того, він схожий на конвенцію, використану в книзі О'Рейлі: "Програмування вбудованих систем із засобами розробки C та GNU". Особисто мені подобається TitleCase у назвах функцій. Я думав перейти на нижчуCamelCase у функції внутрішніх зв'язків (які я назвав приватними у своєму питанні).
JeffV

3
@Chris Lutz, я згоден, від усієї душі. У всіх випадках, коли це можливо, необхідно зберегти на вузькому рівні. Зауважимо, що насправді є три сфери, про які ми обговорюємо: локальна для функції, локальна для модуля (відсутність зовнішньої зв'язку до змінної) та глобальна сфера із зовнішнім зв’язком. У вбудованих системах зазвичай є змінні "глобальний модуль". Отже, слід обережно визначити глобалістів із зовнішнім зв’язком, щоб вони могли бути зведені до мінімуму та розуміти взаємодії модулів. Тут корисний префікс "g_".
JeffV

46
Мені подобається префікс глобальних змінних //.
plafer

Відповіді:


128

Найголовніше тут - послідовність. З цього приводу я дотримуюся конвенції кодування GTK +, яку можна узагальнити так:

  1. Усі макроси та константи в кришках: MAX_BUFFER_SIZE, TRACKING_ID_PREFIX.
  2. Структуруйте назви та typedef у верблюді: GtkWidget, TrackingOrder.
  3. Функції, що функціонують на структурах: класичний стиль C: gtk_widget_show(), tracking_order_process().
  4. Покажчики: тут нічого фантазії: GtkWidget *foo, TrackingOrder *bar.
  5. Глобальні змінні: просто не використовуйте глобальні змінні. Вони злі.
  6. Функції, які існують, але їх не слід викликати безпосередньо, або мати незрозуміле використання, або будь-що інше: одна або декілька підкреслень на початку: _refrobnicate_data_tables(), _destroy_cache().

13
У шостому пункті я вважаю за краще використовувати staticі пропускати префікс модуля, тож якби gtk_widget_show()функція була з областю файлу, вона стане просто widget_show()доданою статичним класом зберігання.
Серпень Карлстром

27
Додаткове зауваження щодо пункту 6: Стандарт C містить деякі правила щодо резервування імен, які починаються з _реалізації та подальшого використання. Є кілька винятків із назв, починаючи з, _але, на мою думку, не варто проблем запам'ятовувати. Безпечне правило - ніколи не використовувати імена, починаючи з _коду. Відповідна стаття C FAQ: c-faq.com/~scs/cgi-bin/faqcat.cgi?sec=decl#namespace
jw013

5
№2, більш конкретно, верхній чохол з верблюда або паскаль . Верблюжий футляр або нижній корпус верблюда використовують нижній регістр на першій букві.
Клінт Пахл

9
Що з локальними багатослівними змінними? my_var чи myVar?
Дін Гурвіц

4
Global variables: just don't use global variables. They are evil.- якщо ви не працюєте над вбудованим проектом і у вас є 1024 байти оперативної пам’яті та 8 МГц процесора.
Каміль

30

"Вказівники на структуру" не є об'єктами, яким не потрібне застереження про іменування для їх покриття. Вони просто struct WhatEver *. НЕ приховуйте факту, що є вказівник, пов'язаний з розумним і "очевидним" typedef. Він не виконує ніяких цілей, довший на друк і руйнує рівновагу між декларацією та доступом.


29
+1 для матеріалу "не приховувати вказівники", хоча ця відповідь не стосується більшої частини решти запитань (поки що).
Джонатан Леффлер

1
@unwind, я схильний погоджуватися. Однак іноді вказівник не призначений для зовнішньої відміни, і він є скоріше ручкою для споживача, ніж фактичним вказівником на структуру, яку він буде використовувати. Ось для чого я і залишив TitleCasePtr. typedef structure {поля} MyStruct, * MyStructPtr;
JeffV

Я видаляю TitleCasePtr, це відволікає увагу від фактичного питання.
JeffV

1
-1 від мене, оскільки декларація типу вказівника зменшує захаращення, особливо у підписах функцій, а "дисбаланс" між декларацією та доступом відображається лише у файлі реалізації - клієнт не має (не повинен) доступу безпосередньо до членів поля.
Серпень Карлстром

1
@AugustKarlstrom Fine. Я не розумію, що так "тільки" у файлі реалізації, чи не є це також код? Я не трактував питання лише як про "зовнішні" імена. Весь код - це "реалізація" на якомусь рівні.
розмотайте

17

Ну по-перше, у C немає публічних / приватних / віртуальних функцій. Це C ++, і він має різні умови. У З зазвичай:

  • Константи в ALL_CAPS
  • Підкреслює розмежування слів у структурах чи назвах функцій, навряд чи ви бачите випадок верблюда в С;
  • Структури, typedefs, союзи, члени (об'єднань та structs) та значення enum, як правило, мають менший регістр (на мій досвід), а не конвенцію C ++ / Java / C # / і т.д. про те, щоб зробити першу літеру великою літерою, але, мабуть, це можливо в C теж.

C ++ є складнішим. Тут я бачив справжню суміш. Футляр для верблюдів для імен класів або малих + підкреслень (на моєму досвіді частіше буває верблюд) Структури використовуються рідко (і зазвичай тому, що бібліотека вимагає їх, інакше ви б використовували класи).


@cletus, я це розумію. Під приватними я маю на увазі функції, які не піддаються зовнішньому заголовку модуля і не призначені для використання кодом, зовнішнім для модуля. Загальнодоступні будуть модульні функції API, призначені для зовнішнього використання.
JeffV

3
Ви можете вважати статичні функції приватними; питання не згадує віртуального. Але +1 для "рідко бачу верблюд у С".
Джонатан Леффлер

2
Я думаю, що Джефф означав external linkage"публічні функції" та internal linkage"приватні функції".
pmg

1
Я бачив константи, що починаються з ak, а також у: kBufferSize. Не впевнений, звідки це походить.
JeffV

2
ALL_CAPSчасто також використовується для значення перерахунків.
caf

14

Ви знаєте, мені подобається, щоб це було просто, але зрозуміло ... Тож ось що я використовую, на мові C:

  • Тривіальні змінні : i,n,cі т. Д. (Лише одна буква. Якщо одна літера не зрозуміла, то зробіть її локальною змінною)
  • Локальні змінні :lowerCamelCase
  • Глобальні змінні :g_lowerCamelCase
  • Змінні змін :ALL_CAPS
  • Змінні вказівника : додайте p_до префікса. Для глобальних змінних це було б gp_var, для локальних змінних p_var, const змінних p_VAR. Якщо далеко використовуються покажчики, тоді використовуйте fp_замість p_.
  • Структури : ModuleCamelCase(Модуль = повна назва модуля або абревіатура з 2-3 літер, але все ще в CamelCase.)
  • Структуруйте змінні учасника :lowerCamelCase
  • Перерахунки :ModuleCamelCase
  • Значення Enum :ALL_CAPS
  • Публічні функції :ModuleCamelCase
  • Приватні функції :CamelCase
  • Макроси :CamelCase

Я набираю свої структури, але використовую те саме ім'я і для тегу, і для typedef. Тег не призначений для звичайного використання. Натомість бажано використовувати typedef. Я також пересилаю декларувати typedef в заголовку загального модуля для інкапсуляції, щоб я міг використовувати ім'я typedef'd у визначенні.

Повний struct приклад :

typdef struct TheName TheName;
struct TheName{
    int var;
    TheName *p_link;
};

Я нічого не знаю про рамки qt, але ви можете писати свій код у будь-якому форматі стилю. Наскільки я не знаю, ніщо не стримує вас від цього.
SeanRamey

10

Кодування в C #, java, C, C ++ і об'єктивному C одночасно, я прийняв дуже просту і чітку конвенцію про іменування, щоб спростити своє життя.

Перш за все, вона покладається на потужність сучасних IDE (таких як eclipse, Xcode ...), з можливістю отримувати швидку інформацію шляхом наведення курсору миші або клавіші ctrl ... Прийнявши це, я придушив використання будь-якого префікса, суфікса та інші маркери, які просто даються IDE.

Потім, конвенція:

  • Будь-які імена ОБОВ'ЯЗКОВО мають бути читабельним реченням, що пояснює, що у вас є. На кшталт "це моя конвенція".
  • Тоді чотири способи отримати конвенцію з речення:
    1. THIS_IS_MY_CONVENTION для макросів, членів перерахунків
    2. ThisIsMyConvention для імені файлу, імені об'єкта (клас, структура, перерахунок, об'єднання ...), ім'я функції, ім'я методу, typedef
    3. глобальні та локальні змінні,
      параметри, структури та об'єднання елементів цього_is_my_convention
    4. thisismyconvention [необов'язково] дуже локальні та тимчасові змінні (такі як індекс циклу for ())

І це все.

Це дає

class MyClass {
    enum TheEnumeration {
        FIRST_ELEMENT,
        SECOND_ELEMENT,
    }

    int class_variable;

    int MyMethod(int first_param, int second_parameter) {
        int local_variable;
        TheEnumeration local_enum;
        for(int myindex=0, myindex<class_variable, myindex++) {
             localEnum = FIRST_ELEMENT;
        }
    }
}

8

Я б рекомендував не змішувати футляр верблюда та виділення підкреслення (як ви запропонували для членів структури). Це заплутано. Ви б подумали, ага, у мене get_lengthтак, мабуть, мабуть, make_subsetі тоді ви дізнаєтесь, що це насправді makeSubset. Використовуйте принцип найменшого здивування та будьте послідовні.

Мені здається, CamelCase корисно вводити імена, як структури, typedefs та enums. Це про все, хоча. Для всіх інших (назви функцій, назви членів структури та ін.) Я використовую підкреслення_separation.


1
Так, головне в будь-якій угоді про іменування - передбачуваність та послідовність. Крім того, оскільки сама бібліотека C використовує всі малі літери з _ для інтервалу, я рекомендую використовувати її просто так, щоб вам не довелося мати справу з двома різними умовами іменування в проекті (якщо припустити, що ви не пишете обгортку навколо libc, щоб зробити це відповідає вашому іменуванню .. але це
валово

Він також використовує typedefs з " t" на кінці, але я не бачу, щоб хтось рекомендував це. Насправді, стандартна бібліотека навіть непослідовна: div_t (stdlib.h) - це структура і так само tm (time.h). Крім того, погляньте на членів структури tm, всі вони мають префікс tm, який здається безглуздим і негарним (IMO).
JeffV

1
"Мені здається, що CamelCase корисно вводити імена ..." Якщо ви запускаєте її з великої літери, це фактично PascalCase.
Tagc

7

Ось (мабуть) незвичайний, який я знайшов корисним: ім'я модуля в CamelCase, потім підкреслення, потім функція або ім'я файлу в CamelCase. Так, наприклад:

Bluetooth_Init()
CommsHub_Update()
Serial_TxBuffer[]

2
Не настільки незвично, але дуже корисно.
chux

3

Мене бентежить одне: Ви плануєте створити нову конвенцію про іменування для нового проекту. Як правило, у вас має бути конвенція про іменування, яка є загальнонаціональною чи командною. Якщо у вас вже є проекти, які мають будь-яку форму конвенції про іменування, ви не повинні змінювати конвенцію на новий проект. Якщо вищезгадана конвенція - це просто кодифікація вашої існуючої практики, то ви золотий. Чим вона відрізняється від існуючих де-факто стандартів, тим важче буде набути розуму в новому стандарті.

Про єдину пропозицію, яку я додам, це те, що мені подобається _t в кінці типів у стилі uint32_t та size_t. Мені це дуже С-іш, хоча деякі можуть скаржитися, що це просто "зворотна" угорська.


3
Ну, умовні положення тут повсюдно і непослідовні, тому я маю намір документувати її. Крім того, саме тому я прошу. Щоб побачити, що таке консенсус громади.
JeffV

Я розумію той біль. Але має бути деякий підмножина ваших існуючих конвенцій, який є найпопулярнішим. Ви повинні почати там, а не на випадковій веб-сторінці в Інтернеті. Крім того, ви повинні запитати інших своїх чортів, що вони вважатимуть за добро.
jmucchiello

7
Я вважаю, що імена типів, що закінчуються на _t, зарезервовані стандартом POSIX.
caf

4
Ім'я, що закінчується _t, зарезервоване. Див. Gnu.org/software/libc/manual/html_node/Reserved-Names.html , "Імена, які закінчуються на" _t ", зарезервовані для додаткових імен типів."
Étienne

2

Також слід подумати про порядок слів, щоб полегшити автоматичне завершення імені .

Хороша практика: назва бібліотеки + назва модуля + дія + тема

Якщо частина не є актуальною, просто пропустіть її, але принаймні слід вказати назву модуля та дію.

Приклади:

  • Ім'я функції: os_task_set_prio, list_get_size,avg_get
  • визначте (зазвичай тут немає жодної дії ):OS_TASK_PRIO_MAX

0

Їх може бути багато, в основному IDE диктують деякі тенденції, і конвенції C ++ також підштовхують. Для С зазвичай:

  • UNDERSCORED_UPPER_CASE (макроозначення, константи, члени перерахунків)
  • underscored_lower_case (змінні, функції)
  • CamelCase (спеціальні типи: структури, перерахунки, спілки)
  • uncappedCamelCase (стиль oppa Java)
  • UnderScored_CamelCase (змінні, функції під типом просторів імен)

Угорські позначення для глобальних компаній є нормальними, але не для типів. І навіть для банальних імен, будь ласка, використовуйте принаймні два символи.


-1

Я думаю, що це може допомогти для початківців: Названня конвенцій змінних у c

  1. Ви повинні використовувати алфавітні символи (az, AZ), цифри (0-9) та Under Score (_). Заборонено використовувати будь-які спеціальні символи, такі як:%, $, #, @ тощо. Отже, ви можете використовувати ім’я користувача як змінну, але не можете використовувати користувача та ім’я .
  2. Не можна використовувати пробіл між словами. Таким чином, ви можете використовувати ім'я користувача або ім’я користувача або ім'я користувача як змінну, але не можете використовувати ім’я користувача .
  3. Неможливо почати називати цифрою. Отже, ви можете використовувати user1 або user2 як змінну, але не можете використовувати 1user .
  4. Це чутливі до регістру мови. Великі і малі регістри є значущими. Якщо ви використовуєте таку змінну, як ім’я користувача, тоді ви не можете використовувати USERNAME або Ім'я користувача для використання батьком.
  5. Не можна використовувати жодне ключове слово (char, int, if, for, while тощо) для оголошення змінної.
  6. Стандарт ANSI розпізнає довжину 31 символу для імені змінної

Цей пост чітко спрямований на обговорення назв конвенцій , а не обмежень . Перелічені вами речі - це ви навіть не можете зробити, оскільки це синтаксичні помилки.
Чейз
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.