#ifdef __cplusplus
// C++ code
#else
// C code
#endif
The structure is this.
My question is, how to actually trigger the #ifdef on?
I mean, in program? What code I write can turn #ifdef on?
For example, in this case.
is that
#define __cplusplus
will turn it on?
"#define __cplusplus"
will let it on?
Yes, it will "let it on".
__cplusplus should be automatically defined by C++ compiler. C++ uses different name mangling and the macro often used to make C headers compatible with C++:
#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif
Just compile it with a C++ compiler and __cplusplus is defined automatically in that case.
The C++ Standard enforces that __cplusplus will always be defined in C++ programs. The C Standard obviously does not. This means that the user need go to no effort to enable this machinery.
A C++ compiler defines this automatically.
Since this starts with two consecutive underscores, it is reserved. You are not allowed to define it yourself (i.e., attempting to do so gives undefined behavior).
Related
I want to undefine and redefine the __cplusplus macro am getting however compilation error:__cplusplus was not declared in this scope
#define TEMP_VERSION __cplusplus // temporary macro to hold the __cplusplus containt
#undef __cplusplus
#define __cplusplus TEMP_VERSION // redefine __cplusplus
#define AA 111
#undef AA
#define AA 111
int main()
{
cout << "__cplusplus = "<<__cplusplus<<endl; // It doesn't work
cout << "AA = "<<AA<<endl; // It works
return 0;
}
Question 1: Why it is not working with the __cplusplus but works with AA
I know that this is really ugly but the reason why am undefining the macro is that I am using a third party Software where they are missusing the #ifdef __cplusplus, I mean the content of the #ifdef __cplusplus ... #endif is wrong. So instead of changing their software I choosed to do the following
#define TEMP_VERSION __cplusplus
#undef __cplusplus
#include <third_party_sw.h>
#define __cplusplus TEMP_VERSION
Question 2: What do you think is it a good approach ?
From the C++ standard ([cpp.predefined, 3-4]):
The values of the predefined macros (except for __FILE__ and __LINE__)
remain constant throughout the translation unit. If any of the
pre-defined macro names in this subclause, or the identifier defined,
is the subject of a #define or a #undef preprocessing directive, the
behavior is undefined.
In other words, the __cplusplus macro isn't just something that the compiler starts out by defining before handing control over to you; it is an immutable constant, which cannot be changed and is an error to attempt to change.
As for whether it would be a good approach if it were possible: Depends on the context, but probably not. These sorts of "fool the header" hacks (#define private public, anyone?) are seldom effective and never safe.
EDIT: Oh, also incidentally, even if you did have a macro it was legal to save/restore, that wouldn't be the right way to do it. See Can I redefine a C++ macro then define it back?.
Question 1: Why it is not working with the __cplusplus but works with AA
Because __cplusplus is a pre-defined macro, and behaviour of (un-)defining it is undefined:
stadard draft [cpp.predefined]
If any of the pre-defined macro names in this subclause, or the identifier defined, is the subject of a #define or a #undef preprocessing directive, the behavior is undefined. ...
AA is not a pre-defined macro, nor is the indentifier reserved. It is OK to (re-)define it.
Question 2: What do you think is it a good approach ?
(Re-)defining reserved identifiers is never a good approach. Even redefining user defined macros is a dubious proposition.
Ideal approach might be to fix the third party software, if possible. Alternatively, you could write a custom header for the software which doesn't have the problem.
It's because __cplusplus is pre-defined by the compiler.
Technically, it's the pre-processor that defines them, but depending on which compiler invokes the pre-processor, the output may differ. Try running this:
$ g++ -dM -E - </dev/null
The output is all the pre-processor defines that (in this case) the pre-processor run by this command produces.
Mind you __cplusplus does not appear there. It's built-in for every C++ compilation unit.
(The same works when substituting clang++ for g++.)
What does the C++ macro __cplusplus contain and expand to?
Does the macro __cplusplus always, even in oldest C++ implementation, contain and expand to a numeric value?
Is it safe to use #if __cplusplus
or should we use instead of that #ifdef __cplusplus?
Conclusion (added later)
From comments and accepted answer:
__cplusplus expands to a number representing the standard's version, except pre-standard C++ in the early 90s (which simply expanded to 1).
Yes, even in oldest C++ implementation (expands to a numeric value).
No, #ifdef should be used when header is shared with C-language (because some C-compilers will warn when #if checks undefined macro).
Yes, it always does expand to numeric value and its meaning is the version of C++ standard that is being used. According to cppreference page, __cplusplus macro should expand to:
199711L (until C++11),
201103L (C++11),
201402L (C++14),
201703L (C++17),
202002L (C++20)
The difference between #if and #ifdef directives is that #ifdef should be used to check whether given macro has been defined to allow a section of code to be compiled.
On the other hand #if (#else, #elif) directives can be used to check whether specified condition is met (just like typical if-condition).
__cplusplus is required to be defined by the C++ standard. For C++11 or higher __cplusplus > 199711L should hold true.
Does the macro __cplusplus always, even in oldest C++ implementation,
contain and expand to a numeric value?
Yes it does.
19.8 C++11
__cplusplus
The integer literal 201703L. [ Note: It is intended that future
versions of this International Standard will replace the value of this
macro with a greater value. — end note ]
C++98
__cplusplus The name
_
_cplusplus is defined to the value 199711L when compiling a C
++ translation unit. 143)
Unfortunately, the __cplusplus macro has the value 199711 in MS Visual Studio 2022, regardless of the specified C++ standard. Use _MSVC_LANG instead. See VS comment.
This seems to work:
#if defined(_MSVC_LANG) // MS compiler has different __cplusplus value.
# if _MSVC_LANG < 201703
# error Please compile for C++17 or higher
# endif
#else // All other compilers.
# if __cplusplus < 201703
# error Please compile for C++17 or higher
# endif
#endif
People recommend #ifdef for conditional compilation by a wide margin. A search for #ifdef substantiates that its use is pervasive.
Yet #ifdef NAME (or equivalently #if defined(NAME) and related #ifndef NAME (and #if !defined(NAME)) have a severe flaw:
header.h
#ifndef IS_SPECIAL
#error You're not special enough
#endif
source.cpp
#include "header.h"
gcc -DIS_SPECIAL source.cpp
will pass, obviously, as will
source1.cpp
#define IS_SPECIAL 1
#include "header.h"
But, so will
source0.cpp
#define IS_SPECIAL 0
#include "header.h"
which is quite the wrong thing to do. And some C++ compilers, passed a file processed in C mode (due to extension or command-line option) effectively do #define __cplusplus 0. I have seen things break when
#ifdef __cplusplus
extern "C" {
#endif
/* ... */
#ifdef __cplusplus
}
#endif
was processed in C mode, where extern "C" is invalid syntax, because __cplusplus was in fact automatically defined to 0.
On the other hand, this behaves correctly for all compilers:
#if __cplusplus
extern "C" {
#endif
/* ... */
#if __cplusplus
}
#endif
Why do people still use #ifdef in this scenario? Are they simply unaware that #if works perfectly fine on undefined names? Or is there an actual disadvantage to #if vs #ifdef for conditional compilation?
Obviously, #ifdef does have valid uses, such as providing default values for configurable parameters:
#ifndef MAX_FILES
#define MAX_FILES 64
#endif
I'm only discussing the case of flag testing.
Why do people still use #ifdef in this scenario?
Personal opinion: it's marginally easier to control from the command line. I prefer -DOPTION over -DOPTION=1.
Also, existence of a name is clearly binary. I don't have to be able to handle {0, non-zero, undefined}.
Are they simply unaware that #if works perfectly fine on undefined names?
I wasn't aware. What are the semantics of this? Is an undefined name assumed to be 0? Do I want to have to explain that to the guy who barely understands the preprocessor to begin with?
Or is there an actual disadvantage to #if vs #ifdef for conditional compilation?
To me, the binary nature of #ifdef/#ifndef of name existence is a clarity benefit.
Also, my primary usage of either construct is for include guards. That pattern is cleanest with #ifndef.
I cannot speak to why people in general prefer #ifdef over #if, but I can at least say why I do. Based on introspection just now (since you asked -- I've never considered it explicitly before), there are 2 reasons:
1) I prefer my macros (which I try to use sparingly) to have the most straightforward semantics as possible, and correspondingly as "type free" as possible. I assume that macros, if they have any type at all, are either "type free functions" (note: here I would strongly prefer templates, but there are times for everything...) or basically just boolean flags. Hence, even assigning a value of 1 to a macro is stretching it for me. (For example, what should it mean if you have #define _cplusplus 2? Should that be different in any way than 1?)
2) This last bit about them being "flags" goes along with the fact that I mostly use these for things I specify on the command line (or in the IDE) as conditional compilation flags. Indeed, on my software team, when we're writing C++, we're basically "prohibited" from using macros for anything else. And even in the conditional compilation case, we try to avoid them if we can solve the problem some other way (such as via modularity).
Both of these reasons relate to that same underlying assumption that macro use is to be avoided as much as possible (in C++) and so should not need the complexities of types or opaque semantics. If you don't make this assumption (and it's less common when programming in C, I know), then that changes things such that I imagine your points about #if might hold more sway.
I would like something like:
#define C_OR_CPP(C__, CPP__) #ifdef __cplusplus\
CPP__\
#else\
C__\
#endif
Is it possible?
Maybe some dirty hack with #include ?
Reason:
I make a header where a struct uses a member variable of type vector<stuff>*, but in C i want it to simply be void*, you know.
TIA
What's the problem with
#ifdef __cplusplus
#define C_OR_CPP(C, CPP) CPP
#else
#define C_OR_CPP(C, CPP) C
#endif
(Leaving names with double underscore to the implementation per phresnel remark)
My English is poor, and I'm sorry for language mistakes and typos if any.
If #ifdef must not wrap the macro invocation, there is a solution not so graceful.
g++ only:
You may try this in selective occasions. But if there are commas in a or b, workarounds are still needed.
It's simply based on the fact that __cplusplus is defined to "1" when in a C++ environment and remains itself while not.
#define SELECT1(a, b) a
#define SELECT__cplusplus(a, b) b
#define xcat(a,b) a##b
#define concat(...) xcat(__VA_ARGS__)
#define C_OR_CPP(C, CPP) concat(SELECT, __cplusplus)(C, CPP)
C_OR_CPP(1, 2)
Other Environments
Check the __cplusplus macro, a compiler that comforming to standard C++ should generate
#define __cplusplus value
and value should >= 199711L
Not in C++. But you can
#ifdef __cplusplus
# define CPP
#else
# define C
#endif
I assume this is just a pathological example by you. Note also that double underscore is reserved to library implementors (see 17.6.4.3.2 Global names).
vector, but in C i want it to simply be void, you know.
So, what speaks against a solution like
struct Foo {
#ifdef __cplusplus
...
#else
...
#endif
};
or what speaks against providing different APIs for different programming languages?
AProgrammer already given you the right answer, but the answer to the "is it possible" part of the question is no. Macro expansion doesn't occur until after all preprocessor directives have been handled, so any macro that expands into a #define or #ifdef will be passed to the compiler as regular source text, which will cause the compiler to yak.
The question title should say it all, but here's an example of what sort of thing I'm looking for:
#ifndef THE_IDENTIFIER_THAT_WOULD_INDICATE_BEING_COMPILED_AS_CPLUSPLUS
/*
* Example of something that would matter.
*/
typedef enum _bool bool;
enum _bool { false, true };
#endif
What is the identifier? It's bugging me severely, as I know I've seen code that does this before.
I'm using GCC, by the way.
(I'm surprised I couldn't find a duplicate somewhere on SO. If someone else can find one, feel free to redirect me and close this as a dupe.)
#ifndef __cplusplus
If I remember correctly.
The identifier is __cplusplus
#ifdef __cplusplus
#error NO C++ PLEASE
#endif
#ifdef __cplusplus
with a few really ancient compilers (early versions of cfront and a couple of ports) it was c_pluplus, IIRC.
#ifdef __cplusplus
#ifdef __cplusplus
I think the file extension matters too, if the C++ compiler is given a .c file it will compile it as C code. i have nothing to back this up though.
The identifier you are looking for is __cplusplus, which can be used like this:
#ifdef __cplusplus
// Code being compiled as C++.
#endif