#On leading underscores and other wide-spread formatting un-conventions in C/C++

| 3 MIN READ
Feature coming soon...

This is one of those live posts, meaning I’ll update it whenever I come across a new “convention”

It’s been more than a month since my last post… but I’m back .

Honestly, it’s really, really hard to come up with things to write about for a blog. That, plus the fact that I’m new to both malware and writing, doesn’t make it easy. The other day, I was talking to a really good colleague about this, specifically about the expectations and the high bar we sometimes (or most of the times) set for ourselves, and he said something that kind of clicked (not exactly this, but kinda): “There’s no need to try to anticipate what people will or won’t like, just write something!”

And I mean, he’s not wrong. There’s no need to find the “perfect” topic. There’s not even a need to try to find something that we think people will like or be interested in. We can’t anticipate that. If we could, I’d just be a fortune-teller.

Sometimes, even the most common topics are enough, as long as they’re well presented of course. The internet is filled with mediocre content, and nowadays, with the rise of AI, even more so. My aim is to create content that’s actually interesting enough for people to read and use for their own stuff. Hopefully, this post is just that.

After this rant, let’s get down to business.

A common “convention” for header files that I’ve seen used almost everywhere (Stack Overflow, uni classes, GitHub, etc.) is _NAME_OF_HEADER_H_. That plus the C/C++ header include guards EXTERNAL LINK TO:

https://en.wikipedia.org/wiki/Include_guard
prevent the same header from being included multiple times when compiling, i.e. this1:

Headers without include guards
Headers without include guards

However, that “convention”, which might come as a surprise to many people, is wrong.

The C++ implementation requirements EXTERNAL LINK TO:

https://timsong-cpp.github.io/cppwp/lex.name#3
specifies the rules to determine whether an identifier is reserved for use by the language, or not. C11’s section 7.1.3 EXTERNAL LINK TO:

https://port70.net/~nsz/c/c11/n1570.html#7.1.3
contains the rules for C, which are mostly the same (surprising, I know lol). And based on that, we can put together the following table2:

PatternConditionsExample
Begins with two underscoresReserved__MY_HEADER_H__
Begins with underscore and uppercase letterReserved_MY_HEADER_H_
Begins with underscore and something elseReserved in global scope (includes macros)_example
Contains two consecutive underscoresReserved in C++ (but okay in C)exam__ple

Those examples apply to everything, not just headers.

Header Guards

So, when it comes to Header Guards, the fix is simple: remove the leading and trailing underscores from the guard’s directive.

Incorrect:

Toggle Line Numbers
Copy Code
1
2
3
4
5
6
#ifndef _MY_HEADER_H_
#define _MY_HEADER_H_

...

#endif // _MY_HEADER_H_

Correct:

Toggle Line Numbers
Copy Code
1
2
3
4
5
6
#ifndef MY_HEADER_H
#define MY_HEADER_H

...

#endif // MY_HEADER_H

Private functions (or variables)

As you might imagine, there’s another common wrong convention that is really popular: prefixing private functions (or variables) with an underscore.

Instead, what one should use (I’m talking about functions here) is the static keyword, which scopes the function to the file where it is defined in. In practical terms, this means the symbol is not externally visible. This allows us to define a private function, so that:

  1. We can have two static functions with the same name in different files without getting name collisions
  2. We can define helper or internal functions intended for internal use that cannot be called from outside their intended scope

Incorrect:

Toggle Line Numbers
Copy Code
1
2
3
4
int _x;
void _myPrivateFunction(void) {
	...
}

Correct:

Toggle Line Numbers
Copy Code
1
2
3
4
int x;
static void myPrivateFunction(void) {
	...
}

Be good!