C preprocessor direct expansion - c++

Hi I've a problem with my cpp macros:
#define DATA_TYPE_B uchar
#define DATA_TYPE_A DATA_TYPE_B //line 2
#undef DATA_TYPE_B
#define DATA_TYPE_B double
DATA_TYPE_A A;
DATA_TYPE_B B;
this wil give me
double A;
double B;
instead of
uchar A;
double B;
because line 2 doesn't expand DATA_TYPE_B, how can i force that expansion?

When the preprocessor sees the use of DATA_TYPE_A it replaces it with DATA_TYPE_B, and then it replaces DATA_TYPE_B with its definition, which is double. It doesn't keep notes about what the definition of DATA_TYPE_B used to be.

you say to the compiler: everything with DATA_TYPE_A replace with DATA_TYPE_B
and then everything with DATA_TYPE_B replace with double

Take a look at #pragma push_macro/#pragma pop_macro (originally limited to MSVC but apparently now supported by both gcc and clang), they allow you to temporarily redefine macro values then revert to the prior value.
Unfortunately macro values are not evaluated until actual expansion so in the case of:
#define macroA float
#define macro B macroA
#undef macroA
#define macroA double
macroB var;
'var' simply is going to expand to double.
But with a compiler that supports push_macro:
#define macroA float
#define macroB macroA
#pragma push_macro("macroA")
#undef macroA
#define macroA double
macroB var1; // var1 is a double
#pragma pop_macro("macroA")
macroB var2; // var2 is a float

I found a possible solution to my problem replacing line 2 by something like:
#if DATA_TYPE_B==uchar
#define DATA_TYPE_A uchar
#elif DATA_TYPE_B==float
#define DATA_TYPE_A float
#elif DATA_TYPE_B==uint
#define DATA_TYPE_A uint
#else
#error Unknown DATA_TYPE_B
#endif
That is a bit ugly and i wish there was just some expansion or evaluation macro though, think I have to write such a macro using such if statements. :-/
Also these camparisons can't be made directly but I have to replace the strings by integers it seems.. :-/

Related

Setting macro-variable-value in macro-function C++

I need to call a function which call a macro-function to change macro-value in runtime.
This code isn't compiled:
#define MY_MACRO 32
#define SET_MY_MACRO_VAL(IS_TRUE)(MY_MACRO=(IS_TRUE)?16:U32)
In function SET_MY_MACRO_VAL
> error: lvalue required as left operand of assignment
#define SET_MY_MACRO_VAL(IS_TRUE)(MY_MACRO=(IS_TRUE)?16:U32)
^
in expansion of macro 'SET_MY_MACRO_VAL'
SET_MY_MACRO_VAL(True);
^
Macro value are replaced BEFORE compile time by the preprocessor and do not exist at run time.
It is not a variable it is simply a way of using text for the value "32".
If you do this :
#define MY_MACRO 32
#define SET_MY_MACRO_VAL(IS_TRUE)(MY_MACRO=(IS_TRUE)?16:U32)
It will be expanded to this
#define MY_MACRO 32
#define SET_MY_MACRO_VAL(IS_TRUE)(32=(IS_TRUE)?16:U32)
What you can do is use a #define
#ifdef SET_MACRO_VAL_32
#define MY_MACRO 32
#else
#define MY_MACRO 16
#endif
Or use a conditionnal macro if you prefer
#if (IS_TRUE>0)
#define MY_MACRO 32
#else
#define MY_MACRO 16
#endif
Edit :
In C++, you shouldn't really need macro though. You can use template and / or constexpr variable for compile-time value. In C++17 you can even use constexpr if.

macro definition containing #pragma

I am trying to define the following macro:
#if defined(_MSC_VER)
#define PRAGMA_PACK_PUSH(n) __pragma(pack(push, n))
#define PRAGMA_PACK_POP() __pragma(pack(pop))
#else
#define PRAGMA_PACK_PUSH(n) #pragma (pack(push, n))
#define PRAGMA_PACK_POP() #pragma (pack(pop))
#endif
But i get the following error on Linux -
error: '#' is not followed by a macro parameter
#define PRAGMA_PACK_PUSH(n) #pragma (pack(push, n))
and it points to the first ')' in the statment
How can i define a macro that contains a #?
Solution Update:
As stated in this thread Pragma in define macro the syntax that worked is:
#if defined(_MSC_VER)
#define PRAGMA_PACK_PUSH(n) __pragma(pack(push, n))
#define PRAGMA_PACK_POP() __pragma(pack(pop))
#else
#define PRAGMA_PACK_PUSH(n) _Pragma("pack(push, n)")
#define PRAGMA_PACK_POP() _Pragma("pack(pop)")
#endif
How can i define a macro that contains a #?
You can't (define a macro that contains a directive, that is. # can still be used in macros for stringization and as ## for token concatenation). That's why _Pragma was invented and standardized in C99. As for C++, it's definitely in the C++11 standard and presumably the later ones.
You can use it as follows:
#define PRAGMA(X) _Pragma(#X)
#define PRAGMA_PACK_PUSH(n) PRAGMA(pack(push,n))
#define PRAGMA_PACK_POP() PRAGMA(pack(pop))
With that,
PRAGMA_PACK_PUSH(1)
struct x{
int i;
double d;
};
PRAGMA_PACK_POP()
preprocesses to
# 10 "pack.c"
#pragma pack(push,1)
# 10 "pack.c"
struct x{
int i;
double d;
};
# 15 "pack.c"
#pragma pack(pop)
# 15 "pack.c"
As you can see, the _Pragmas are expanding to #pragma directives.
Since _Pragma is standard, you should be able to avoid the #ifdef here if Microsoft supports it.

Can BOOST_PP_DEFINED be implemented?

Is it possible to write a function-like C preprocessor macro that returns 1 if its argument is defined, and 0 otherwise? Lets call it BOOST_PP_DEFINED by analogy with the other boost preprocessor macros, which we can assume are also in play:
#define BOOST_PP_DEFINED(VAR) ???
#define XXX
BOOST_PP_DEFINED(XXX) // expands to 1
#undef XXX
BOOST_PP_DEFINED(XXX) // expands to 0
I'm expecting to use the result of BOOST_PP_DEFINED with BOOST_PP_IIF:
#define MAGIC(ARG) BOOST_PP_IIF(BOOST_PP_DEFINED(ARG), CHOICE1, CHOICE2)
In other words, I want the expansion of MAGIC(ARG) to vary based on whether ARG is defined or not at the time that MAGIC is expanded:
#define FOO
MAGIC(FOO) // expands to CHOICE1 (or the expansion of CHOICE1)
#undef FOO
MAGIC(FOO) // expands to CHOICE2 (or the expansion of CHOICE2)
I also found it interesting (and somewhat surprising) that the following doesn't work:
#define MAGIC(ARG) BOOST_PP_IIF(defined(arg), CHOICE1, CHOICE2)
Because apparently defined is only valid in the preprocessor when used as part of an #if expression.
I somewhat suspect that the fact that boost preprocessor doesn't already offer BOOST_PP_DEFINED is evidence for its impossibility, but it can't hurt to ask. Or, am I missing something really obvious about how to achieve this.
EDIT: To add some motivation, here is why I want this. The traditional way to do "API" macros to control import/export is to declare a new set of macros for every library, which means a new header, etc. So if we have class Base in libbase and class Derived in libderived, then we have something like the following:
// base_config.hpp
#if LIBBASE_COMPILING
#define LIBBASE_API __declspec(dllexport)
#else
#define LIBBASE_API __declspec(dllimport)
// base.hpp
#include "base_config.hpp"
class LIBBASE_API base {
public:
base();
};
// base.cpp
#include "base.hpp"
base::base() = default;
// derived_config.hpp
#if LIBDERIVED_COMPILING
#define LIBDERIVED_API __declspec(dllexport)
#else
#define LIBDERIVED_API __declspec(dllimport)
// derived.hpp
#include "derived_config.hpp"
#include "base.hpp"
class LIBDERIVED_API derived : public base {
public:
derived();
};
// derived.cpp
#include "derived.hpp"
derived::derived() = default;
Now, obviously, each of the _config.hpp header would really be a lot more complex, defining several macros. We could probably pull out some of the commonalities into a generic config_support.hpp file, but not all. So, in an effort to simplify this mess, I wondered if it would be possible make this generic, so that one set of macros could be used, but that would expand differently based on which _COMPILING macros were in play:
// config.hpp
#define EXPORT __declspec(dllexport)
#define IMPORT __declspec(dllimport)
#define API_IMPL2(COND) BOOST_PP_IIF(COND, EXPORT, IMPORT)()
#define API_IMPL(ARG) API_IMPL2(BOOST_PP_DEFINED(ARG))
#define API(LIB) API_IMPL(LIB ## _COMPILING)
// base.hpp
#include "config.hpp"
class API(LIBBASE) base {
public:
base();
};
// base.cpp
#include "base.hpp"
base::base() = default;
// derived.hpp
#include "config.hpp"
#include "base.hpp"
class API(LIBDERIVED) derived : public base {
public:
derived();
};
// derived.cpp
#include "derived.hpp"
derived::derived() = default;
In other words, when compiling base.cpp, API(LIBBASE) would expand to __declspec(dllexport) because LIBBASE_COMPILING was defined on the command line, but when compiling derived.cpp API(LIBBASE) would expand to __declspec(dllimport) because LIBBASE_COMPILING was not defined on the command line, but API(LIBDERIVED) would now expand to __declspec(dllexport) since LIBDERIVED_COMPILING would be. But for this to work it is critical that the API macro expand contextually.
It looks like you could use BOOST_VMD_IS_EMPTY to implement the required behavior. This macro returns 1 if its input is empty or 0 if its input is not empty.
Trick based on the observation that when XXX is defined by #define XXX, empty parameter list passed to BOOST_VMD_IS_EMPTY(XXX) during expansion.
Sample implementation of MAGIC macro:
#ifndef BOOST_PP_VARIADICS
#define BOOST_PP_VARIADICS
#endif
#include <boost/vmd/is_empty.hpp>
#include <boost/preprocessor/control/iif.hpp>
#define MAGIC(XXX) BOOST_PP_IIF(BOOST_VMD_IS_EMPTY(XXX), 3, 4)
#define XXX
int x = MAGIC(XXX);
#undef XXX
int p = MAGIC(XXX);
For Boost 1.62 and VS2015 preprocessor output will be:
int x = 3;
int p = 4;
This approach has a number of flaws, e.g. it's not working if XXX defined with #define XXX 1. BOOST_VMD_IS_EMPTY itself has limitations.
EDIT:
Here is the implementation of the required API macros based on BOOST_VMD_IS_EMPTY:
// config.hpp
#ifndef BOOST_PP_VARIADICS
#define BOOST_PP_VARIADICS
#endif
#include <boost/vmd/is_empty.hpp>
#include <boost/preprocessor/control/iif.hpp>
#define EXPORT __declspec(dllexport)
#define IMPORT __declspec(dllimport)
#define API_IMPL2(COND) BOOST_PP_IIF(COND, EXPORT, IMPORT)
#define API_IMPL(ARG) API_IMPL2(BOOST_VMD_IS_EMPTY(ARG))
#define API(LIB) API_IMPL(LIB ## _COMPILING)
Let's see what preprocessor will output for:
// base.hpp
#include "config.hpp"
class API(LIBBASE) base {
public:
base();
};
When LIBBASE_COMPILING defined, GCC output:
class __attribute__((dllexport)) Base
{
public:
Base();
};
When LIBBASE_COMPILING is not defined, GCC output:
class __attribute__((dllimport)) Base
{
public:
Base();
};
Tested with VS2015 and GCC 5.4 (Cygwin)
EDIT 2:
As #acm mentioned when parameter defined with -DFOO it's same as -DFOO=1 or #define FOO 1. In this case approach based on BOOST_VMD_IS_EMPTY is not working. To overcome it you can use BOOST_VMD_IS_NUMBER (thnx to #jv_ for the idea). Implementation:
#ifndef BOOST_PP_VARIADICS
#define BOOST_PP_VARIADICS
#endif
#include <boost/vmd/is_number.hpp>
#include <boost/preprocessor/control/iif.hpp>
#define EXPORT __declspec(dllexport)
#define IMPORT __declspec(dllimport)
#define API_IMPL2(COND) BOOST_PP_IIF(COND, EXPORT, IMPORT)
#define API_IMPL(ARG) API_IMPL2(BOOST_VMD_IS_NUMBER(ARG))
#define API(LIB) API_IMPL(LIB ## _COMPILING)
It's not a pure is defined check, but we can get all the way to checking for a particular token name.
Annotating a first principles solution based on Cloak from Paul Fultz II:
First provide the ability to conditionally choose text based on macro expansion to 0 or 1
#define IIF(bit) PRIMITIVE_CAT(IIF_, bit)
#define IIF_0(t, f) f
#define IIF_1(t, f) t
Basic concatenation
#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a##__VA_ARGS__
Logical operators (compliment and and)
#define COMPL(b) PRIMITIVE_CAT(COMPL_, b)
#define COMPL_0 1
#define COMPL_1 0
#define BITAND(x) PRIMITIVE_CAT(BITAND_, x)
#define BITAND_0(y) 0
#define BITAND_1(y) y
A method to see whether a token is or is not parens "()"
#define CHECK_N(x, n, ...) n
#define CHECK(...) CHECK_N(__VA_ARGS__, 0, )
#define PROBE(x) x, 1,
#define IS_PAREN(x) CHECK(IS_PAREN_PROBE x)
#define IS_PAREN_PROBE(...) PROBE(~)
Note IS_PAREN works because "IS_PAREN_PROBE X" turns in to one arg in CHECK(), where as "IS_PAREN_PROBE ()" turns into PROBE(~) which turns into ~, 1. At which point we can pick up the 1 from CHECK
Another utility to eat some macro arguments as needed
#define EAT(...)
Here, we take advantage of blue painting (the thing which prevents naively recursive macros) to check whether or not two tokens are the same. If they are this collapses to (). Otherwise not, which we can detect via IS_PAREN.
This relies on COMPARE_XXX identity macros existing for any given symbol
#define PRIMITIVE_COMPARE(x, y) IS_PAREN(COMPARE_##x(COMPARE_##y)(()))
We add an IS_COMPARABLE trait for that helper
#define IS_COMPARABLE(x) IS_PAREN(CAT(COMPARE_, x)(()))
We work backwards to EQUAL by checking if both args are comparable, then converting to primitive_compare if they are. If not, we're not equal and eat the following args.
#define NOT_EQUAL(x, y) \
IIF(BITAND(IS_COMPARABLE(x))(IS_COMPARABLE(y))) \
(PRIMITIVE_COMPARE, 1 EAT)(x, y)
EQUAL is the compliment
#define EQUAL(x, y) COMPL(NOT_EQUAL(x, y))
And finally, the macro we actually want.
First we enable compare for "BUILDING_LIB"
#define COMPARE_BUILDING_LIB(x) x
Then our actual deciding macro, which is an integer if on whether a symbol resolves to "BUILDING_LIB"
#define YES_IF_BUILDING_LIB(name) IIF(EQUAL(name, BUILDING_LIB))("yes", "no")
#include <iostream>
#define FOO BUILDING_LIB
int main(int, char**) {
std::cout << YES_IF_BUILDING_LIB(FOO) << "\n";
std::cout << YES_IF_BUILDING_LIB(BAR) << "\n";
}
Which outputs:
yes
no
See his great blogpost (that I cribbed from): C Preprocessor tricks, tips, and idioms
Since you intend to use FOO as file-level switch that you control, I suggest that you use a simpler solution. The suggested solution is easier to read, less surprising, requires no dirty magic.
Instead of #define MAGIC(ARG) BOOST_PP_IIF(BOOST_PP_DEFINED(ARG), CHOICE1, CHOICE2) you simply -D with MAGIC=CHOICE1 or MAGIC=CHOICE2 per file.
You don't have to do it for all files. The compiler will tell you when you used MAGIC in a file, but did not make a choice.
If CHOICE1 or CHOICE2 is a major default you don't wish to specify, you can use -D to set default for all files and -U + -D to change your decision per file.
If CHOICE1 or CHOICE2 is lengthy, you can #define CHOICE1_TAG actual_contents in your header file where you originally intended to define MAGIC and then -D with MAGIC=CHOICE1_TAG, because CHOICE1_TAG will be automatically expanded into actual_contents.

C++ `ifdef` with concatenation of macros values

Can I achieve something similar to following code:
#define MODULE base
#if defined (MODULE ## _dll) <-- this should do `#ifdef base_dll`
...
#else
...
#endif
second line is obviously wrong. Can I do this somehow?
Thanks
I don't think it is possible to check the definition of token-pasted macro like that (at least I don't know the way) but you can do this:
#define JOIN_INTERNAL(a,b) a ## b
#define JOIN(a,b) JOIN_INTERNAL(a,b)
// switch 1/0
#define base_dll 1
#define MODULE base
#if JOIN(MODULE,_dll)
// the base_dll is 1
#else
// the base_dll is 0 or not defined (in MSVC at least)
#endif
Perhaps if you describe what do you actually want to achieve there might be another way to do that.

Cross-platform code label macro?

In MSVC & C#, #pragma region can be used to label a code section.
Similarly, in GCC/Clang, #pragma mark can accomplish the same thing.
Is it possible to define a single macro such as CODELABEL(label) which will work for both compilers?
Basically, I'd like to avoid having to do the following:
#ifdef _WIN32
#pragma region Variables
#else
#pragma mark Variables
#endif
bool MyBool;
int MyInt;
#ifdef _WIN32
#pragma region Methods
#else
#pragma mark Methods
#endif
void MyMethod();
void AnotherMethod();
... and instead, do something like this:
CODELABEL( Variables )
bool MyBool;
int MyInt;
CODELABEL( Functions )
void MyMethod();
void AnotherMethod();
Is something like this possible?
Yes, in C++11, you can use _Pragma, since using #pragma in a macro definition is not allowed:
#ifdef _WIN32
#define PRAGMA(x) __pragma(x) //it seems like _Pragma isn't supported in MSVC
#else
#define PRAGMA(x) _Pragma(#x)
#endif
#ifdef _WIN32
#define CODELABEL(label) PRAGMA(region label)
#else
#define CODELABEL(label) PRAGMA(mark label)
#endif
The dance with PRAGMA is to satisfy _Pragma requiring a string literal, where side-by-side concatenation of two string literals (e.g., "mark" "section label") doesn't work.
According to this topic, the following should work.
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
#ifdef _WIN32
#define LABEL region
#else
#define LABEL mark
#endif
and then
#pragma STR(LABEL) Variables
bool MyBool;
int MyInt;
#pragma STR(LABEL) Functions
void MyMethod();
void AnotherMethod();
As far as Windows and macOS are concerned, since Xcode 12 and Visual Studio 2019, you can easily use this syntax that works ok on both platforms:
#pragma region mark -
#pragma region mark Whathever Your Label
Xcode silently ignores the 'region' token while VS takes the 'mark' token as part of the label, which is a minor cosmetic issue, IMHO.