I am trying to define the value of a macro based on some condition like
#define DEV NO
#if DEV == YES
#define API_ENDPOINT_HOST #"https://my-dev.com/"
#else
#define API_ENDPOINT_HOST #"http://my-qa.com/"
#endif
But even though I have defined DEV as No, it is always taking API_ENDPOINT_HOST as #"https://my-dev.com/". What is wrong here?
Even Uli's answer is correct (as everyone expected), I want to explain it in more detail:
In PP phase an undefined identifier in an #if directive is replaced with 0. NO and YES are not defined anymore as macro as it has been in the past, but became literals. So they are undefined in PP phase.
Your second line is:
#if DEV == YES
DEV is replaced with NO …,
#if NO == YES
… what is undefined as YES is. Therefore both are replaced by 0:
#if 0 == 0
That's obviously true.
NO and YES are Objective-C constructs. The preprocessor runs before the Objective-C compiler, so does not know YES or NO yet. Usually people use 0 and 1 in preprocessor defines.
Alternatively, just define your symbol and then use #ifdef instead of #if.
#define DEV
#ifdef DEV
#define API_ENDPOINT_HOST #"https://my-dev.com/"
#else
#define API_ENDPOINT_HOST #"http://my-qa.com/"
#endif
Related
If I create a preprocessor macro named DEBUG for the Debug configuration of a project's target with the value 1, and not for the Release configuration, I find that using
#if DEBUG
...
#endif
compiles for Release builds too.
Firstly, is it checking if DEBUG is defined and after that if it evaluates to true? If yes, is it ok (or recommended) to use it this way instead of
#ifdef DEBUG
#if DEBUG
...
#endif
#endif
?
It's not recommended to use #if VARIABLE without checking that VARIABLE has been defined.
When #if evaluates the expression, it does the following:
It expands all macros in the expression (which means that an symbol which has not been #defined will be unchanged.)
It parses the result as an integer arithmetic expression, replacing any identifier with the integer 0.
So if DEBUG has not been #defined as a macro,
#if DEBUG
will be the same as
#if 0
which will also have the same effect as #ifdef DEBUG.
If you define DEBUG on the command-line with -DDEBUG, then there is an implicit
#define DEBUG 1
before the file is preprocessed, with the result that
#if DEBUG
is the same as
#if 1
which is also the same as #ifdef DEBUG.
However. If you did the following:
#define DEBUG
#if DEBUG
// ... stuff
#endif
the the #if will expand to:
#if
and you'll get an error message:
file.m:2:6: error: #if with no expression
As a result, it is unwise to use #if VARIABLE, unless you know for sure that VARIABLE has been defined as an integer.
Modern Xcode already provides a definition for DEBUG when building in debug mode.
The difference between #ifdef DEBUG and #if DEBUG is that #ifdef DEBUG will be true when the symbol is defined, no matter what value has been defined.
Thus, #define DEBUG=0 will be true for #ifdef DEBUG because it has a defined value (it will also be true for #define DEBUG for the same reason).
However, #if DEBUG will only be true if DEBUG has been defined with a non-zero value.
Suppose I have two libraries ABC, XYZ and two variables ABC_FOUND XYZ_FOUND in CMakeLists.txt. In a config.h.in file, I have the following lines
#define __USE_ABC__ #ABC_FOUND#
#define __USE_XYZ__ #XYZ_FOUND#
If I do configure_file(config.h.in config.h), the output config.h file will be changed to
#define __USE_ABC__ ON
#define __USE_XYZ__ OFF
My question is how can I convert the ON/OFF options into 1/0, in other word, my desired output config.h should be
#define __USE_ABC__ 1
#define __USE_XYZ__ 0
Define ABC_FOUND to either 0 or 1 with
#cmakedefine01 #ABC_FOUND#
Use an intermediate variable in either environment to change it to USE_ABC.
Likely, you should use #cmakedefine instead of hard defines (see examples e.g. here)
But please remember that in the case of #cmakedefine you get a configuration header where "enabled features" (in terms of CMake if() command) are #define-d to a supplied value, while "disabled features" are #undef-ined. So you should test them not with #if <something> but rather with #ifdef <something>.
What's wrong here:
#define CONTROLS_OFFSET 100
#ifdef CONTROLS_OFFSET//Unterminated conditional directive it says
#define FIND_MAIN_MENU 3
Why do i get this error?
An #ifdef, like an #if, needs to be balanced by an #endif. In this case, that would probably go immediately after your #define line.
Something like this:
#ifdef DEBUG
NSLog (#"This is a test");
#endif
I have tested a bit of assembler on Linux using the AT&T syntax. One thing that struck me was that the book I was reading was written from a 32-bit standpoint. Thus, all sizes would have to be changed to the correct 64-bit versions for me. Or I could (which I did) assemble the code using the --32 flag for as and the -melf_i386 flag for ld when linking. I have also adapted some of the code and to run on Windows under Cygwin.
But that got me thinking. Is there a way to do ifdef like checks in assembler to do one thing if I'm on Windows and another under Linux and also handle 32 vs 64 bit that way? For example to have a .globl _start under Linux and a .globl _main under Windows.
Or is this handled by checking before assembling and having different source files to assemble based on the result of the checks?
I.e. foo_linux.s and foo_windows.s
If so, how do you overcome that fact that you will not know which .s files you will use, and thus have to include, when you are creating your program?
For example, say that we have a socket_linux.s and a socket_windows.s. They both present an identical interface but do the OS specific work associated to sockets. But when I work with the sockets in my program I will not know if I need the Windows or Linux version included. So I would be kinda screwed :)
So how is this handled in Assembler? In C++ for example I could include my socket.h and socket.cpp and wrap all the Linux and Windows specific code in #ifdef statements.
If you use GCC to compile your files and name them .S (with uppercase S) or .sx, it will pass them through the preprocessor before invoking the assembler.
From the docs:
file.s
Assembler code.
file.S
file.sx
Assembler code which must be preprocessed.
You can add -v to the command line to see how the various sub-processes are invoked.
in MASM (.asm), you can use ifdef, ifndef and the likes, as:
ifdef X64
endif
When writing for different platforms you can define some macro for loading target specific files:
FILE target.h
#if defined(__arm__)
#define target "arm"
#elif defined(__x86_64__)
#if defined(_WIN64)
#define target "win64"
#else
#define target "linux64" // all non-Win share the same calling convention
#endif
#else
// 32bit defs
#endif
Then you can include target specific files with the macro, two string literals successively get one single literal:
#include "target.h"
#include "target_specific_code_" target ".h"
It includes one of these files:
target_specific_code_arm.h
target_specific_code_win64.h
target_specific_code_linux64.h
...
EDIT:
Like this, you can also define target specific assembler instructions for later use in inline assembly:
#ifdef ...
#define ASM_PP_LOAD_WORD "movi "
#else
#define ASM_PP_LOAD_WORD "mov "
#endif
or as macro
#ifdef ...
// when using intel assembler there is a different
// order of parameters
#define ASM_PP_LOAD_WORD(a, b) "movi " #b ", " #a
#else
#define ASM_PP_LOAD_WORD(a, b) "mov " #a ", " #b
#endif
If I add a macro "FOO=bar" under GCC_PREPROCESSOR_DEFINITIONS (or Preprocessor Macros if you use XCode"), what would be the best way to access the value of "FOO"?
Currently, I use the clumsy:
#define MACRO_NAME(f) #f
#define MACRO_VALUE(f) MACRO_NAME(f)
#ifdef FOO
NSLog(#"%s", MACRO_VALUE(FOO));
#else
NSLog(#"undefined");
#endif
This will output "bar"
Surely, there must be a better/cleaner way?
What you are doing is the way to stringize (or stringify) macro values. The indirection is unavoidable.
This is mentioned in the GCC preprocessor manual section (archived link) that Rob linked to:
#define xstr(s) str(s)
#define str(s) #s
#define foo 4
str (foo)
==> "foo"
xstr (foo)
==> xstr (4)
==> str (4)
==> "4
NSLog(#"%s", #FOO);
See Stringification. It's the technique you're already using. What was wrong with it?