Comprehensive Interpretation of the C Language Code Standards by the curl Team

Consistent code style aids in team collaboration and code reviews. The most commonly used style in the industry is Google’s, but in this section, we will explore something different: the coding standards of the curl team, a tool that we frequently use.

To briefly introduce curl, it is very useful for transferring data in command lines or scripts, and many of you have likely used it. Its source code can be viewed on GitHub.

https://github.com/curl/curl

Comprehensive Interpretation of the C Language Code Standards by the curl Team

Next, we will examine the C language development standards of curl from several aspects.

  • Naming

  • Indentation

  • Comments

  • Long Lines

  • Braces

  • ‘else’ on the next line

  • No space before parentheses

  • Use boolean conditions

  • No assignment in conditions

  • New blocks on new lines

  • Spaces around operators

  • No parentheses for return values

  • Parentheses for sizeof parameters

  • Column alignment

  • Platform-specific code

  • Do not typedef structs

Naming

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

File-local functions should be declared as static, preferably with lowercase names.

Indentation

Use spaces only for indentation, not tabs. Each new opening brace should use two spaces.

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

Comments

Since we are writing C89 code, // comments are not allowed. They were introduced in the C99 standard. Only use /* comments */.

/* This is a comment */

Long Lines

The source code in curl should never exceed 79 columns, even in the era of modern large and high-resolution screens, for two reasons:

  1. Narrow columns are easier to read than wide columns. This is why newspapers have used columns for decades, even centuries.
  2. Narrow columns allow developers to more easily display multiple code snippets side by side in different windows. It enables displaying two or three source code windows side by side on the same screen, along with multiple terminal and debugging windows.

Braces

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

if(age < 40) {
  /* Obviously a young person */
}

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

if(!x)
  continue;

For functions, the opening brace should be on a separate line:

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

‘else’ on the next line

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

if(age < 40) {
  /* Obviously a young person */
}
else {
  /* Possibly a grumpy person */
}

No space before parentheses

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

while(1) {
  /* Infinite loop */
}

Use boolean conditions

In if/while conditions, we prefer to test condition values, such as boolean values with TRUE or FALSE, pointers with NULL or != NULL, and integers with zero or non-zero, rather than:

result = do_something();
if(!result) {
  /* There was a problem */
  return result;
}

No assignment in conditions

To enhance readability and reduce complexity in conditions, avoid variable assignments in if/while conditions. This style is discouraged:

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

Instead, express it more clearly:

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

New blocks on new lines

Never write multiple statements on the same line, even for short if() conditions.

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

Never do this:

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

Spaces around operators

Please use spaces on both sides of operators in C expressions. The suffix (), [], ->, ., ++, — and unary +, -, !, ~, & operators should not have spaces.

Example:

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 for return values

No extra parentheses in ‘return’ statements:

int works(void)
{
  return TRUE;
}

Parentheses for sizeof parameters

When using the sizeof operator in code, we prefer to add parentheses around its parameters:

int size = sizeof(int);

Column alignment

Some statements cannot be completed on a single line due to long lines, difficult-to-read statements, or due to other style guidelines mentioned above. In such cases, statements span multiple lines.

If a continuous line is part of an expression or sub-expression, you should align it at the appropriate column to clearly indicate which part of the statement it belongs to. Operators should not start on a continuous line. 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))
  /* No request for HTTP/1.0 and is a GET or HEAD request */
  return TRUE;

If there are no parentheses, use the default indentation:

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

Use opening parentheses when calling functions:

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

Align with the “current 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 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 config-[system].h files for other systems.

We also encourage using macros/functions that may be null or defined as constants during libcurl builds to make the code seamless. Like this example, where the magic() function works differently based 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

While structs can be used, do not typedef them. Use struct name to identify them:

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

Do not do 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

Hot Update: Step-by-Step Implementation of an Industrial-Grade Thread Pool

Comprehensive Interpretation of the C Language Code Standards by the curl Team

Comprehensive Interpretation of the C Language Code Standards by the curl Team

Leave a Comment