C11: The function called at program startup is named main.
C11: The implementation declares no prototype for this function.
C11: The main function shall be defined with a return type of int
Style; functions; have the opening brace at the beginning of the next line.
C11: The main function defined with no parameters:
int main(void)
{
/* ... */
}
C11: The main function defined with two parameters...
Style; main function; with two parameters:
int main(int argc, char* argv[])
{
/* ... */
}
Style C23; function pointer param; use array notation; to be explicit that the pointer can not be nullptr
.
Style C23; main function; with two parameters:
int main(int argc, [[maybe_unused]] char* argv[argc+1])
{
/* ... */
}
Style C23; null; Do not use the macro NULL
; use nullptr
instead.
Style; selection statements; always use brackets; to be explicit for the secondary block.
Style; selection statements; the first bracket for the secondary block begins on the same line:
if (true) {
/* ... */
} else if (false) {
/* ... */
} else {
/* ... */
}
Style; iteration statements; always use brackets; to be explicit for the secondary block.
Style; iteration statements; the first bracket for the secondary block begins on the same line:
for (size_t ix = 0; ix < 5; ix += 1) {
/* ... */
}
Style; declaring pointer; left-binding rule:
/*
* When declaring pointer data or a function that returns a pointer type,
* the preferred use of ''*'' is adjacent to the type.
*/
char* name;
unsigned long long memparse(char* ptr, char* retptr[]);
char* match_strdup(substring_t* s);
char const* const path_name[[deprecated]];
Style; declaring pointer; right-binding rule:
/*
* When declaring pointer data or a function that returns a pointer type,
* the preferred use of ''*'' is adjacent to the name.
*/
char *name;
unsigned long long memparse(char *ptr, char **retptr);
char *match_strdup(substring_t *s);
char const *const path_name[[deprecated]];
Style; declaring pointer; follow the pattern that the project uses; prefere the left-binding rule over the right-binding rule in most cases.
Style; function pointer param; char s[]
, char *s
, and char* s
are equivalent, use the latter.
Style; pointer; use a name like px or ptr for pointer variables: https://godbolt.org - example
#include <stdlib.h> void swap(int* px, int* py) { // int* px -- (px) is a pointer-to type (int) int tmp = *px; // *px -- value-of (px) *px = *py; *py = tmp; } int main(void) { int a = 2; int b = 3; swap(&a, &b); // &a -- address-of (a) return EXIT_SUCCESS; }
Style; pointer and string example: https://godbolt.org - example
#include <stdio.h>
#include <stdlib.h>
/* Do not use this style. */
char *bad_style(char *sp)
{
int x = 5, *ip = &x;
printf("x = %d\n", x);
printf("ip = %ld\n", ip);
printf("x = %d\n", *ip);
printf("%s\n", sp);
return sp;
}
/* Use this style. */
char* better_style(char* str)
{
int x = 5;
int* px = &x;
printf("x = %d\n", x);
printf("ip = %ld\n", px);
printf("x = %d\n", *px);
printf("%s\n", str);
return str;
}
int main(void)
{
char str[] = "foobaz C style";
char* ptr = better_style(bad_style(str));
if (str == ptr) {
printf("same memory address");
}
return EXIT_SUCCESS;
}
Style; if statement; do not compare to 0
, false
, or true
:
if (return_code != 0) {
/* Use the logic instead that an if statement checks if it is non zero. */
} else if (success == true) {
/* Use the boolean value directly like ''if (success) {}'' */
}
The Boolean data type in C is also considered an unsigned type.
The values false
and true
, corresponding to 0
and 1
, so there are no negative values.
You will probably rarely need bool variables.
Style C23; variables; always use the zero initialization syntax:
int a = {}; /* Do not use this style */
int b = { 0 };
int c = { 2 };
int many_zeros[100] = {}; /* Available in C11; do not use this style. */
int many_zeros[100] = { 0 }; /* Available in C11 */
int many[100] = { [50] = 3, [90] = 7 }; /* Available in C11 */
int more[10] = {
[3] = 3,
[4] = 7, /* When each initializer is on its own line then use trailing comma. */
};
Inspiration:
Then use the Linux kernel coding style
#include <stdio.h>
#include <stdlib.h>
/* The <stdlib.h> header shall define NULL as described in <stddef.h>. */
#include <stdbool.h>
/* Before C23; the names bool as well as the constants false and true only came through the inclusion of <stdbool.h>. */
#include <stddef.h>
int main(int argc, char* argv[])
{
if (argc != 2) {
fprintf(stderr, "Usage: %s <file>\n", argv[0]);
exit(EXIT_FAILURE);
}
FILE* file = fopen(argv[1], "r");
if (file == NULL) {
perror(argv[1]);
return EXIT_FAILURE;
}
/* Other code omitted */
if (fclose(file)) {
return EXIT_FAILURE;
}
#define pattern_size 4
bool pattern[pattern_size] = { [1] = true, [2] = true };
for (size_t ix = 0; ix < pattern_size; ix += 1) {
if (pattern[ix]) {
printf("1\n");
} else {
printf("0\n");
}
}
return EXIT_SUCCESS;
}
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
int main(int argc, [[maybe_unused]] char* argv[argc+1])
{
if (argc != 2) {
fprintf(stderr, "Usage: %s <file>\n", argv[0]);
exit(EXIT_FAILURE);
}
FILE* file = fopen(argv[1], "r");
if (file == nullptr) {
perror(argv[1]);
return EXIT_FAILURE;
}
/* Other code omitted */
if (fclose(file)) {
return EXIT_FAILURE;
}
constexpr size_t pattern_size = { 4 };
bool pattern[pattern_size] = { [1] = true, [2] = true };
for (size_t ix = { 0 }; ix < pattern_size; ix += 1) {
if (pattern[ix]) {
printf("1\n");
} else {
printf("0\n");
}
}
return EXIT_SUCCESS;
}