Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there certain keywords that should not be "#defined" by me?

I am developing a platform layer for my application in C/C++.

I would like to

#define WINDOWS // on Windows machines

#define ANDROID // on Android phones

Is it a bad idea to define very common keywords like "WINDOWS" or "ANDROID" due to conflict with other libraries and would it make sense to prefix these keywords with something:

#define MYLIB_WINDOWS // Not used by any other 3rdparty libraries

#define MYLIB_ANDROID

like image 854
Markall Avatar asked Jul 07 '18 09:07

Markall


People also ask

Do keywords have to be exact?

Do keywords have to be exact in 2020? No. Google now uses smart algorithms to match related terms based on user intent. Search is smart enough to serve the same content for related terms and alternate spellings, even when not an exact match query.

Do keywords really matter?

Keywords are important because they tell search engines about the content of your website's page. “Keyword” is also a term that's used to refer to the words and phrases that people enter into a search engine to find information that they're looking for.


Video Answer


2 Answers

I would like to

Beware of exposing macros with 'common' names in your library's header files.

Beware also of commonly named macros in private code - particularly if it #includes (either directly or indirectly) other library's headers.

You cannot rely on the hope that all library maintainers are as well-behaved as you.

and would it make sense to prefix these keywords with something:

In general, yes.

A great example of this is the BOOST suite of libraries. BOOST takes great care to ensure that all macros exported by its header files have the prefix BOOST_. It is no coincidence that the prefix matches the library's namespace name of boost::.

In summary, if your library is implemented in a namespace (and it should be, otherwise you're guilty of polluting the global namespace), please do use a macro prefix that matches it.

Example:

namespace mylib { namespace innerthing { }}

#define MYLIB_ON 1
#define MYLIB_OFF 0
#define MYLIB_SETTING MYLIB_ON
#define MYLIB_INNERTHING_SETTING MYLIB_OFF
like image 150
Richard Hodges Avatar answered Sep 28 '22 00:09

Richard Hodges


TL;DR version

Macros with common name will cause issues sooner or later, so the short answer is "NEVER use a common name for your macro".

SUGGESTION

A very useful approach is to prefix your very simple name with the name of your project, which is pretty common practice in include guards.

PROPER EXPLAINATION (with example)

As an example, in the past I was working on program, specifically on header P(roject), and had to include a file that, through a not too deep include chain, was including a header where you could find a member function named "Log" (call this header C for class).

It just so happened that, through a very different chain of includes, I also imported the definition of a macro named in the same way: "Log". Call this header M for macro.

The result was that when I tried to compile, depending on the order of the includes in my project, I would either be fine or end up with a bug.

The first step a compiler performs is to call the preprocessor on the source file currently being compiled. Every time if finds an #include it literally replaces the line with a copy paste of the whole header you are including. At the end of a preprocessing you have a big file with inside all the code from your source and all the recursively included headers.

If the code in this final file is in the following order (top to bottom of the file):

C

M

P

Then everything is fine, as the macro in M only affects the code after it. If the order is instead:

M

C

P

the preprocessor would sawp the function name with the content of the macro.

Assume the code in M is:

#define Log printf("Oops")

And that the code in C is:

class L {
    void Log(const char* message) { printf("%s\n", message); }
};

After the preprocessor stage each Log line (after macro declaration) would have been replaced with the content of the macro. That is, the code from C now looks like this:

class L {
    void printf("Oops")(const char* message) { printf("%s\n", message); }
};

This code clearly will not compile.

The main issue, though, is that the compiling error will have to do with why that line does not compile, which is not the real problem: macro substitution is.

Note that, depending on the macro and the code being replaced, your code might end up compiling but doing a different thing from the one you coded (e.g. think of a constant value being replaced because your constant is named in the same way as a macro).

USEFUL NOTE

When debugging the worst macro issue I had gcc version 6.something was utterly useless, because it was focusing only on the post-preprocessor code. Clang version 3.something was, as usual, a saving grace: it immediately told me that there was an X11 macro (3 library layers deep from where I was coding!) with a relatively sensible name (long-ish 2 word name). Unluckily a sensible name for your library might be sensible for the library user code too, which is why even rare name are not enough.

Every macro really need that _ prefix.

like image 30
Dirich Avatar answered Sep 27 '22 23:09

Dirich