Перейти к содержанию

Последнее обновление:2026-10-12

Памятка по разработке на C++ с libcurl

Единый стиль кода помогает командной работе и ревью кода; в индустрии чаще всего используется стиль google, а в этом разделе рассмотрим кое-что другое — посмотрим, каковы стандарты кода команды curl, инструмента, которым мы пользуемся довольно часто.

Пару слов о curl: он очень удобен для передачи данных в командной строке или скриптах, вы наверняка им пользовались; исходный код можно посмотреть на github

https://github.com/curl/curl

Теперь рассмотрим стандарты разработки на C команды curl по нескольким аспектам.

Именование

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

Функции, локальные для файла, следует объявлять статическими; рекомендуется использовать строчные буквы в названиях.

Отступы

Используйте для отступов только пробелы, без табуляции. На каждую новую открывающую фигурную скобку — два пробела.

if(something_is_true) {
  while(second_statement == fine) {
    moo();
  }
}

Комментарии

Поскольку пишется код C89, комментарии // не разрешены — они появились только в стандарте C99. Используйте только /* комментарии */.

/* 这是一个注释 */

Длина строк

Исходный код в curl никогда не должен превышать 79 колонок, и даже в эпоху современных больших экранов и высокого разрешения есть две причины это соблюдать:

  1. Более узкие колонки читать легче, чем широкие. Не случайно газеты десятилетиями и даже веками используют колонки.
  2. Более узкие колонки позволяют разработчикам легче размещать несколько фрагментов кода рядом в разных окнах. Это даёт возможность показать на одном экране два-три окна с исходным кодом, а также несколько терминалов и окон отладки.

Фигурные скобки

В выражениях if/while/do/for открывающую фигурную скобку мы пишем на той же строке, что и ключевое слово, а закрывающую — на отдельной строке с тем же уровнем отступа, что и начальное ключевое слово. Вот так:

if(age < 40) {
  /* 显然是年轻人 */
}
Если внутри только один однострочный оператор, скобки можно опустить:

if(!x)
  continue;
Для функций открывающая скобка должна быть на отдельной строке:

int main(int argc, char **argv)
{
  return 1;
}

'else' на следующей строке

При добавлении clauses else к условному выражению с фигурными скобками мы помещаем его на новой строке после закрывающей скобки. Вот так:

if(age < 40) {
  /* 显然是年轻人 */
}
else {
  /* 可能是脾气暴躁的 */
}

Без пробела перед скобкой

В выражениях if/while/do/for между ключевым словом и открывающей скобкой не должно быть пробела. Вот так:

while(1) {
  /* 永远循环 */
}

Используйте булевы условия

В условиях if/while мы предпочитаем проверять значение условия как булево с TRUE или FALSE, указатель с NULL или != NULL, а целое — с нулём или ненулевым значением, а не так:

result = do_something();
if(!result) {
  /* 出现了问题 */
  return result;
}

Не присваивайте в условиях

Для улучшения читаемости и снижения сложности условий избегайте присваивания переменных в условиях if/while. Такой стиль не одобряется:

if((ptr = malloc(100)) == NULL)
  return NULL;
Вместо этого поощряется более ясное выражение:

ptr = malloc(100);
if(!ptr)
  return NULL;

Новый блок на новой строке

Никогда не пишите несколько операторов в одной строке — даже короткие условия if() не исключение.

if(a)
  return TRUE;
else if(b)
  return FALSE;
И никогда так:

if(a) return TRUE;
else if(b) return FALSE;

Пробелы вокруг операторов

Используйте пробелы с обеих сторон операторов в C-выражениях. Исключение — постфиксные (), [], ->, ., ++, -- и унарные +, -, !, ~, & операторы: перед ними пробелов быть не должно.

Примеры:

bla = func();
who = name[0];
age += 1;
true = !false;
size += -2 + 3 *

 (a + b);
ptr->member = a++;
struct.field = b--;
ptr = &address;
contents = *pointer;
complement = ~bits;
empty = (!*string) ? TRUE : FALSE;

Возвращаемое значение без скобок

Не ставьте лишних скобок в операторе 'return':

int works(void)
{
  return TRUE;
}

Аргумент sizeof в скобках

Используя в коде оператор sizeof, мы предпочитаем заключать его аргумент в скобки:

int size = sizeof(int);

Выравнивание по колонкам

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

Если продолжающая строка является частью выражения или подвыражения, следует выравнивать её по подходящей колонке, чтобы было ясно, частью какого оператора она является. Оператор не должен начинаться с продолжающей строки. В остальных случаях придерживайтесь правила отступа в 2 пробела. Вот несколько примеров из libcurl:

if(Curl_pipeline_wanted(handle->multi, CURLPIPE_HTTP1) &&
   (handle->set.httpversion != CURL_HTTP_VERSION_1_0) &&
   (handle->set.httpreq == HTTPREQ_GET ||
    handle->set.httpreq == HTTPREQ_HEAD))
  /* 没有要求 HTTP/1.0 并且是 GET 或 HEAD 请求 */
  return TRUE;
Если скобок нет, используйте отступ по умолчанию:

data->set.http_disable_hostname_check_before_authentication =
  (0 != va_arg(param, long)) ? TRUE : FALSE;
При вызове функции — по открывающей скобке:

if(option) {
  result = parse_login_details(option, strlen(option),
                               (userp ? &user : NULL),
                               (passwdp ? &passwd : NULL),
                               NULL);
}
Выравнивание по «текущей открытой» скобке:

DEBUGF(infof(data, "Curl_pp_readresp_ %d bytes of trailing "
             "server response left\n",
             (int)clipamount));

Платформозависимый код

Используйте #ifdef HAVE_FEATURE для условного кода. Мы избегаем проверки конкретной операционной системы или оборудования в строках #ifdef. HAVE_FEATURE должен генерироваться скриптом configure для Unix-подобных систем, а для остальных систем жёстко задаваться в файлах config-[system].h.

Мы также рекомендуем при сборке libcurl использовать макросы/функции, которые могут быть пустыми или определены как константы, чтобы код был бесшовным. Как в этом примере, где функция magic() работает по-разному в зависимости от условий сборки:

#ifdef HAVE_MAGIC
void magic(int a)
{
  return a + 2;
}
#else
#define magic(x) 1
#endif

int content = magic(3);

Не делайте typedef для структур

Хотя структуры использовать можно, делать для них typedef не следует. Обозначайте их как struct name:

struct something {
   void *valid;
   size_t way_to_write;
};
struct something instance;
Не так:

typedef struct {
   void *wrong;
   size_t way_to_write;
} something;
something instance;
Эта статья переведена с: https://curl.se/dev/code-style.html

Примечание

Это памятка для разработки; рекомендуется сверяться с официальной документацией libcurl и разбирать коды ошибок конкретного проекта.

Похожие темы

Комментарии