C++ macros explanation - c++

Can somebody explain the following code please?
#if 1
// loop type
#define FOR_IS_FASTER 1
#define WHILE_IS_FASTER 0
// indexing type
#define PREINCREMENT_IS_FASTER 1
#define POSTINCREMENT_IS_FASTER 0
#else
// loop type
#define FOR_IS_FASTER 1
#define WHILE_IS_FASTER 0
// indexing type
#define PREINCREMENT_IS_FASTER 0
#define POSTINCREMENT_IS_FASTER 1
#endif
#if PREINCREMENT_IS_FASTER
#define ZXP(z) (*++(z))
#define ZX(z) (*(z))
#define PZ(z) (++(z))
#define ZP(z) (z)
#define ZOFF (1)
#elif POSTINCREMENT_IS_FASTER
#define ZXP(z) (*(z)++)
#define ZX(z) (*(z))
#define PZ(z) (z)
#define ZP(z) ((z)++)
#define ZOFF (0)
#endif
I can understand what the functions are doing but for example
how does the pre-processor choose which ZXP will be execute if we call it later?
What do the 1 and 0 stand for?

The #if 1 triggers the first group of #defines, which set PREINCREMENT_IS_FASTER to 1. Because of this, #if PREINCREMENT_IS_FASTER triggers the first #define ZXP....
There is nothing exceptional about 1 and 0 in this context. The #if preprocessor directive succeeds if its argument is non-zero.
You can switch to the alternate form by changing the #if 1 at the top of the file with #if 0. (Thank you #rabidmachine for the tip.)

I'm probably inclined to agree with UncleBens and suggest that it's done so that you don't understand it, because the whole lot is totally useless.

Related

How to get rid of warnings that precompiler definitions are not definied

There is a file that I downloaded from the Unity web-site
#pragma once
// Standard base includes, defines that indicate our current platform, etc.
#include <stddef.h>
// Which platform we are on?
// UNITY_WIN - Windows (regular win32)
// UNITY_OSX - Mac OS X
// UNITY_LINUX - Linux
// UNITY_IOS - iOS
// UNITY_TVOS - tvOS
// UNITY_ANDROID - Android
// UNITY_METRO - WSA or UWP
// UNITY_WEBGL - WebGL
#if _MSC_VER
#define UNITY_WIN 1
#elif defined(__APPLE__)
#if TARGET_OS_TV //'TARGET_OS_TV' is not defined, evaluates to 0
#define UNITY_TVOS 1
#elif TARGET_OS_IOS //'TARGET_OS_IOS' is not defined, evaluates to 0
#define UNITY_IOS 1
#else
#define UNITY_OSX 1 //'UNITY_OSX' macro redefined
#endif
#elif defined(__ANDROID__)
#define UNITY_ANDROID 1
#elif defined(UNITY_METRO) || defined(UNITY_LINUX) || defined(UNITY_WEBGL)
// these are defined externally
#elif defined(__EMSCRIPTEN__)
// this is already defined in Unity 5.6
#define UNITY_WEBGL 1
#else
#error "Unknown platform!"
#endif
...
The problem is that when I try to include the file in my XCode project I got a warning (put them in comments)
...
#if TARGET_OS_TV //'TARGET_OS_TV' is not defined, evaluates to 0
#define UNITY_TVOS 1
#elif TARGET_OS_IOS //'TARGET_OS_IOS' is not defined, evaluates to 0
#define UNITY_IOS 1
#else
#define UNITY_OSX 1 //'UNITY_OSX' macro redefined
#endif
...
I tried to use #pragma warning(suppress: 4101) and a few similar approaches, but it doesn't help
UPD
...
#ifdef TARGET_OS_TV
#define UNITY_TVOS 1
#elif TARGET_OS_IOS //'TARGET_OS_IOS' is not defined, evaluates to 0
#define UNITY_IOS 1
#else
#define UNITY_OSX 1
#endif
...
Using ifdef helps to get rid of the first warning, but the second one is still in place
UPD2
...
#ifdef TARGET_OS_TV
#define UNITY_TVOS 1
#elifdef TARGET_OS_IOS //Invalid preprocessing directive
#define UNITY_IOS 1
#else
#define UNITY_OSX 1
#endif
...
You should not use #if to test an undefined macro. The warning implies that you should use #ifdef instead.
You may not define a previously defined macro. You could first undefined the old definition, but that's rarely a good idea.
Using ifdef helps to get rid of the first warning, but the second one is still in place
In c++23 you will be able to use #elifdef instead.
Otherwise, you can use #elif defined(the_macro).

Alternative to dynamic creation of variable names

I have a header file (not written by me, which I cannot change) which contains definitions in the following format:
#define SPC_TMASK0_NONE 0x00000000
#define SPC_TMASK0_CH0 0x00000001
#define SPC_TMASK0_CH1 0x00000002
#define SPC_TMASK0_CH2 0x00000004
#define SPC_TMASK0_CH3 0x00000008
#define SPC_TMASK0_CH4 0x00000010
#define SPC_TMASK0_CH5 0x00000020
#define SPC_TMASK0_CH6 0x00000040
#define SPC_TMASK0_CH7 0x00000080
#define SPC_TMASK0_CH8 0x00000100
#define SPC_TMASK0_CH9 0x00000200
#define SPC_TMASK0_CH10 0x00000400
#define SPC_TMASK0_CH11 0x00000800
#define SPC_TMASK0_CH12 0x00001000
#define SPC_TMASK0_CH13 0x00002000
#define SPC_TMASK0_CH14 0x00004000
#define SPC_TMASK0_CH15 0x00008000
#define SPC_TMASK0_CH16 0x00010000
#define SPC_TMASK0_CH17 0x00020000
#define SPC_TMASK0_CH18 0x00040000
#define SPC_TMASK0_CH19 0x00080000
#define SPC_TMASK0_CH20 0x00100000
#define SPC_TMASK0_CH21 0x00200000
#define SPC_TMASK0_CH22 0x00400000
#define SPC_TMASK0_CH23 0x00800000
#define SPC_TMASK0_CH24 0x01000000
#define SPC_TMASK0_CH25 0x02000000
#define SPC_TMASK0_CH26 0x04000000
#define SPC_TMASK0_CH27 0x08000000
#define SPC_TMASK0_CH28 0x10000000
#define SPC_TMASK0_CH29 0x20000000
#define SPC_TMASK0_CH30 0x40000000
#define SPC_TMASK0_CH31 0x80000000
I have a function which is accepts a channel number (0-31) and I want to find the corresponding macro expansion (SPC_TMASK0_NONE, SPC_TMASK0_CH0... etc).
I thought that creating the macro expansion dynamically (as a string) would be the easiest/neatest/cleanest but it seems that I can't do that so can someone suggest a better alternative to go from channel number to macro expansion?
I know that the number corresponding to the macro expansion could be used directly, but this has the potential to change so I need to use the names to ensure correct operation over time.
I really don't want a big if else / switch case - I was thinking of an array with the names in and the channel number is used to select the element but that felt clunky as well.
If you need to map a runtime integer to a macro's value, your best bet is indeed an array. But you don't have to write it yourself!
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/cat.hpp>
constexpr auto channelMask(int channelNumber) {
constexpr std::uint32_t array[] {
#define detail_channelMask_case(z, n, data) \
BOOST_PP_CAT(SPC_TMASK0_CH, n),
BOOST_PP_REPEAT(32, detail_channelMask_case, ~)
#undef detail_channelMask_case
};
return array[channelNumber];
}
This generates the array with the macros 0 to 31, and indexes into it. I leave it to you to handle input limits and the SPC_TMASK0_NONE macro :)

how to comment values under #ifdef in one place

let's imagine we have a C++ project that should work on several platforms (for example, arm/arm64) and we need to have target-specific values for each of them.
Right now we do:
#ifdef PLATFORM_ARM
#define TIMEOUT_VALUE 0
#define OUR_MAGIC_VALUE 1
#elif PLATFORM_ARM64
#define TIMEOUT_VALUE 2
#define OUR_MAGIC_VALUE 3
#endif
where could I place a comment for each defined name that it could be accessed from each definition?
Note: I can't define each value in its own #ifdef like
// a comment for TIMEOUT_VALUE
#ifdef PLATFORM_ARM
#define TIMEOUT_VALUE 0
#elif PLATFORM_ARM64
#define TIMEOUT_VALUE 2
#endif
// a comment for OUR_MAGIC_VALUE
#ifdef PLATFORM_ARM
#define OUR_MAGIC_VALUE 1
#elif PLATFORM_ARM64
#define OUR_MAGIC_VALUE 2
#endif
because I have lists and trees of such values.
Thank you.
Edit 1:
for example, we have 6 targets and 4 of them support a FEATURE,
so we write:
#if defined(ARM)
#define FEATURE 1
#elif defined(ARM64)
#define FEATURE 0
#elif define(MIPS)
#define FEATURE 1
etc... for other platforms.
then I have code that reads this define somewhere:
#if FEATURE
do something. Note that this part can't be described in a target specific file, because it can have the same implementation for several targets.
#endif
and now I want to have a place to describe in general what this FEATURE means and do.
You can define a proxy macro and write a single comment for macro to be used by end user:
#ifdef PLATFORM_ARM
#define TIMEOUT_VALUE_IMPL 0
#define OUR_MAGIC_VALUE_IMPL 1
#elif PLATFORM_ARM64
#define TIMEOUT_VALUE_IMPL 2
#define OUR_MAGIC_VALUE_IMPL 3
#endif
// a comment for TIMEOUT_VALUE
#define TIMEOUT_VALUE TIMEOUT_VALUE_IMPL
// a comment for OUR_MAGIC_VALUE
#define OUR_MAGIC_VALUE OUR_MAGIC_VALUE_IMPL
You may also consider using constants instead of macros.

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.

Substitute expression by value?

I have the following macro:
#define REFLECTABLE(...) \
REFLECTABLE_CONST(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__)==0, __VA_ARGS__)
I ran the pre-processor. It passes to REFLECTABLE_CONST 3==0 instead of 0 or false. In REFLECTABLE_CONST, I am using that value to simulate a conditional as described in this post. So, I need the pre-processor to pass a value. Is there a way to make pre-processor substitute things like 3==0 by false or 0?
I couldn't reproduce BOOST_PP_VARIADIC_SIZE being able to have a result of 0, but if you can, this should work:
#define IS_EMPTY_IMPL0 1
#define IS_EMPTY_IMPL1 0
#define IS_EMPTY_IMPL2 0
#define IS_EMPTY_IMPL3 0
#define IS_EMPTY_IMPL4 0
#define IS_EMPTY_IMPL5 0
#define IS_EMPTY_IMPL6 0
#define IS_EMPTY_IMPL7 0
#define IS_EMPTY_IMPL8 0
#define IS_EMPTY_IMPL9 0
#define IS_EMPTY(...) BOOST_PP_CAT(IS_EMPTY_IMPL, BOOST_PP_VARIADIC_SIZE(__VA_ARGS__))
#define REFLECTABLE(...) \
REFLECTABLE_CONST(IS_EMPTY(__VA_ARGS__), __VA_ARGS__)
Stumbled upon this solution. Just use this instead:
#define REFLECTABLE(...) \
REFLECTABLE_CONST(BOOST_PP_IS_EMPTY(__VA_ARGS__), __VA_ARGS__)