Skip to content

Last updated:2026-10-12

libcurl C++ Development Notes

A unified code style helps team collaboration and code review. The industry mostly uses Google's style; this section offers something different — let's see what the code conventions of the curl team look like, a tool most of us use a lot.

To say a few words about curl: it is very useful for transferring data on the command line or in scripts, and you have surely used it. Its source implementation can be viewed on GitHub:

https://github.com/curl/curl

Below let's look at curl's C language development conventions from several aspects.

Naming

New function and variable names should be logical, understandable, and named according to their purpose.

File-local functions should be declared static; lowercase names are recommended.

Indentation

Use only spaces for indentation, never tabs. Use two spaces for each new open brace.

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

Comments

Since C89 code is being written, // comments are not allowed. They were not introduced until the C99 standard. Use only /* comments */.

/* 这是一个注释 */

Long Lines

Source code in curl should never exceed 79 columns. Even in this age of modern large screens and high resolutions, there are still two reasons to keep this:

  1. Narrow columns are easier to read than wide ones. There is a reason newspapers have used columns for decades and even centuries.
  2. Narrower columns make it easier for developers to display multiple code snippets side by side in different windows. It allows two or three source code windows to be shown side by side on the same screen — along with multiple terminal and debug windows.

Braces

In if/while/do/for expressions, we write the open brace on the same line as the keyword, and then put the closing brace on a line at the same indentation level as the initial keyword. Like this:

if(age < 40) {
  /* 显然是年轻人 */
}

If they contain only a single one-line statement, the braces can be omitted:

if(!x)
  continue;

For functions, the open brace should be written on its own line:

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

'else' on the Next Line

When adding an else clause to a conditional expression using braces, we add it on a new line after the closing brace. Like this:

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

No Space Before Parentheses

When using if/while/do/for expressions, there should be no space between the keyword and the open parenthesis. Like this:

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

Use Boolean Conditions

In if/while conditions we prefer testing the condition's value — booleans against TRUE or FALSE, pointers against NULL or != NULL, and integers against zero or non-zero — rather than:

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

No Assignments in Conditions

For readability and to reduce the complexity of conditions, avoid assigning variables inside if/while conditions. This style is frowned upon:

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

Instead, expressing it more clearly is encouraged:

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

New Block on a New Line

Multiple statements are never written on the same line — not even short if() conditions are an exception.

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

Never like this:

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

Spaces Around Operators

Please use spaces on both sides of operators in C expressions. Exceptions are the postfix (), [], ->, ., ++, -- and unary +, -, !, ~, & operators, which should have no spaces.

Examples:

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;

No Parentheses Around Return Values

Do not add extra parentheses in 'return' statements:

int works(void)
{
  return TRUE;
}

Parenthesize the sizeof Argument

When using the sizeof operator in code, we prefer parentheses around its argument:

int size = sizeof(int);

Column Alignment

Some statements cannot be completed on a single line — because the line is too long, the statement is too hard to read, or because of the other style guidelines above. In such cases the statement spans multiple lines.

If a continuation line is part of an expression or sub-expression, you should align it at the appropriate column so it is clear which part of the statement it belongs to. Operators should not start continuation lines. In other cases, follow the 2-space indentation guideline. Here are some examples from 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;

Without parentheses, use the default indentation:

data->set.http_disable_hostname_check_before_authentication =
  (0 != va_arg(param, long)) ? TRUE : FALSE;

For function calls, use the open parenthesis:

if(option) {
  result = parse_login_details(option, strlen(option),
                               (userp ? &user : NULL),
                               (passwdp ? &passwd : NULL),
                               NULL);
}

Aligned with the "currently open" parenthesis:

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

Platform-Specific Code

Use #ifdef HAVE_FEATURE for conditional code. We avoid checking for specific operating systems or hardware in #ifdef lines. HAVE_FEATURE should be generated by the configure script for Unix-like systems, and they are hardcoded in the config-[system].h files on other systems.

We also encourage using macros/functions that may be empty or defined as constants when libcurl is built, to make the code seamless. Like this example, where the magic() function works differently depending on build-time conditions:

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

int content = magic(3);

Do Not typedef Structs

Although structs can be used, do not typedef them. Refer to them using the struct name form:

struct something {
   void *valid;
   size_t way_to_write;
};
struct something instance;

Not like this:

typedef struct {
   void *wrong;
   size_t way_to_write;
} something;
something instance;

This article is translated from: https://curl.se/dev/code-style.html

Note

This article is a development memo; it is recommended to consult the official libcurl documentation together with your project's specific error codes for troubleshooting.

Comments