#if defined(_WIN32)
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
So the above is the first 4 lines of C language code from a file of some project.
I do know that #if defined (macro name) means that if the macro is defined, the value of the expression is 1 and if not, then it's 0.
So basically, the first two lines will be either 1 or 0 but what would they do? 1 or 0 just sitting alone?
It's defined() which will be evaluated to either 0 or 1 and from that value if will decide if it should go to the body. It's like normal if statement.
So basically, the first two lines will be either 1 or 0 but what would they do? 1 or 0 just sitting alone?
#if expression
won't result in a line replaced by the result of expression but the preprocessor will decide upon the value of expressen in
#if expression
controlled text
#endif /* expression */
if it will process the controlled text or not.
So basically, the first two lines will be either 1 or 0 but what would they do? 1 or 0 just sitting alone?
No, the #if would stay, just the defined() would become 0 or 1.
So assuming for example _WIN32 and _CRT_SECURE_NO_WARNINGS were defined, then the 1st two line you show looked like:
#if 1
#if 0
Those two if-statements control if what is following is taken into account until the next #endif statement.
The above snippet though is incomplete and should look like this:
#if 1
#if 0
#define FOO 42
#endif
#endif
The above would not #define FOO.
The below would not #define FOO as well:
#if 0
#if 1
#define FOO 42
#endif
#endif
The following will define FOO:
#if 1
#if 1
#define FOO 42
#endif
#endif
Back to your example code:
The stuff "controlled" by the outer if-statement
#if defined(_WIN32)
is
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
The stuff "controlled" by the inner if-statement
#if !defined(_CRT_SECURE_NO_WARNINGS)
is
#define _CRT_SECURE_NO_WARNINGS
Related
I'm wondering if it can be written that the prepocessor evaluates assigned constants known at compile time and returns the result as a string. I believe the answer is no or complex, but I'll give a try.
Basically I have constants which are expressed in milliseconds but I want to display the results as secs, therefore divide by 1000, and wonder because all is known at compile time, if the preprocessor can directly put the result of this division into the code rather than eval at runtime.
Example:
#define FREQ_AUTO_WHEN_RELAY_ON 150000UL
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
STR( FREQ_AUTO_WHEN_RELAY_ON/1000UL ) " secs"
would yield to "150000UL/1000UL secs"
which is not I want to display, aka "150 secs"
Thanks
You have to first prepare a header with all possible outputs:
// calculate.h
#if VALUE == 1
#define RESULT 1
#elif VALUE == 2
#define RESULT 2
/* etc. millions of lines */
#elif VALUE == 150
#define RESULT 150
#endif
Then you can do:
#define VALUE FREQ_AUTO_WHEN_RELAY_ON/1000UL
#include "calculate.h"
STR(VALUE)
Similarly, you first have to define a matrix of all possible combinations of values:
#define DIV_1UL_1UL 1
#define DIV_1UL_2UL 0
#define DIV_2UL_1UL 2
/* etc. really millions of lines */
#define DIV_150000UL_1000UL 150
Then you can:
#define DIV(a, b) DIV_##a##_##b
#define XDIV(a, b) DIV(a, b)
STR(XDIV(FREQ_AUTO_WHEN_RELAY_ON, 1000UL))
Can C-preprocessor can output as a string the evaluation of compiled known constants values(e.g. 150000UL/1000UL)?
Yes, but it's not practical. Instead, generate the header file from a build system.
Hi my c code need to consider block of code depending on
#if <condition>
//code block to execute if conditions matches
#endif
Now problem is in my shell script which I run before I compile c code I set ML_ARCH=r8.
I can do check in Makefile as below:
ifeq ($(ML_ARCH), r8)
endif
But for C code how to compare variable against string which is mix of char and number, in preprocessor #if
how to compare in #if condition of preprocessor for string
It is not possible to compare strings in preprocessor.
You can add something unique to r8 to make it longer and define it to a number. You could just #define r8 1, but r8 is a bit short and could be break random code.
// #define ML_ARCH r8
#define ARCH_r8 1
#define ARCH_some_other_arch 2
#define ARCH_etc 3
#define XADD_ARCH(a) ARCH_##a
#define ADD_ARCH(a) XADD_ARCH(a)
#define IS_ARCH(a) (ADD_ARCH(ML_ARCH) == ARCH_##a)
// #if XCONCAT(ARCH_, ML_ARCH) == ARCH_r8
#if IS_ARCH(r8)
Overall, consider doing -D ML_ARCH=ARCH_r8 and then just #if ML_ARCH == ARCH_r8.
When implementing Annex K of the C standard (Bounds-checking Interfaces), there is the following requirement:
The extensions specified in this annex can be "requested" to be declared by defining __STDC_WANT_LIB_EXT1__ to 1, and requested to not be declared by defining that to 0.
Then there is this paragraph:
Within a preprocessing translation unit, __STDC_WANT_LIB_EXT1_ _ shall be defined identically for all inclusions of any headers from subclause K.3. If __STDC_WANT_LIB_EXT1_ _ is defined differently for any such inclusion, the implementation shall issue a diagnostic as if a preprocessor error directive were used.
I wonder how to implement this. I went ahead and naïvely wrote this (to be included in each affected header):
#ifndef __STDC_WANT_LIB_EXT1__
#ifdef __STDC_WANT_LIB_EXT1_PREVIOUS__
#error __STDC_WANT_LIB_EXT1__ undefined when it was defined previously.
#endif
#else
#ifdef __STDC_WANT_LIB_EXT1_PREVIOUS__
#if __STDC_WANT_LIB_EXT1__ != __STDC_WANT_LIB_EXT1_PREVIOUS__
#error __STDC_WANT_LIB_EXT1__ defined to different value from previous include.
#endif
#else
#define __STDC_WANT_LIB_EXT1_PREVIOUS__ __STDC_WANT_LIB_EXT1__
#endif
#endif
This (of course) does not work for a variety of reasons:
Does not catch the case when __STDC_WANT_LIB_EXT1__ is not defined for the first include, but defined for the second (which should also be caught with an #error)
The #define does not take the value of __STDC_WANT_LIB_EXT1__ (prefixing # would take the symbol as string, going through symbol2value(...) would take the 1 as string).
...
...but if taken as pseudocode it showcases the logic behind it.
I am not that well-versed with more intricate preprocessor business like this, as you are usually told to stay away from macro magic. There has to be a way to implement the quoted requirement; it just doesn't "click" for me.
Any ideas?
To complete the [mcve], put the above code into header.h, and this in testme.c:
#define __STDC_WANT_LIB_EXT1__ 0
#include "header.h"
#define __STDC_WANT_LIB_EXT1__ 1
#include "header.h"
int main() {}
This should trigger the "different value" error message.
#HWalters did set me on the right track:
#ifndef __STDC_WANT_LIB_EXT1__
#ifdef __STDC_WANT_LIB_EXT1_PREVIOUS__
#if __STDC_WANT_LIB_EXT1_PREVIOUS__ != -1
#error __STDC_WANT_LIB_EXT1__ undefined when it was defined earlier.
#endif
#else
#define __STDC_WANT_LIB_EXT1_PREVIOUS__ -1
#endif
#else
#ifdef __STDC_WANT_LIB_EXT1_PREVIOUS__
#if __STDC_WANT_LIB_EXT1__ != __STDC_WANT_LIB_EXT1_PREVIOUS__
#error __STDC_WANT_LIB_EXT1__ redefined from previous value.
#endif
#else
#if __STDC_WANT_LIB_EXT1__ == 0
#define __STDC_WANT_LIB_EXT1_PREVIOUS__ 0
#elif __STDC_WANT_LIB_EXT1__ == 1
#define __STDC_WANT_LIB_EXT1_PREVIOUS__ 1
#else
/* Values other than 0,1 reserved for future use */
#define __STDC_WANT_LIB_EXT1_PREVIOUS__ -2
#endif
#endif
#endif
The "thinko" was this line:
#define __STDC_WANT_LIB_EXT1_PREVIOUS__ __STDC_WANT_LIB_EXT1__
Defining the "previous" to an actual value instand of another token makes it work.
The solution is not perfect, though -- all "other" values except 0,1,undefined get lumped together into a single "previous" value (-2), while the letter of the standard says that any redefinition should issue a diagnostic.
I made a mechanism for compiling only selected tests from a sequence of tests by defining the macros:
#define SELECTION(x) ((!defined (RUN_SELECTED_TESTS_ONLY)) || (defined (x)))
#define RUN_SELECTED_TESTS_ONLY
#define TEST_1 //Lets say I want only test1 to be compiled
#if SELECTION(TEST_1) //The line I'm getting the error on.
//code of test 1
#endif
#if SELECTION(TEST_2)
//code of test 2
#endif
While compilation I'm getting the error :
error C2003: expected 'defined id'
I'm getting the error only when TEST_1 or TEST_2 (or both) are defined.
An alternative definition for SELECTION:
#ifdef RUN_SELECTED_TESTS_ONLY
#define SELECTION defined
#else
#define SELECTION(x) 1
#endif
Notes:
Must be defined after RUN_SELECTED_TESTS_ONLY is.
Only works in GNU cpp and other preprocessors similarly permissive about operator defined being the result of a macro expansion.
Example:
#define RUN_SELECTED_TESTS_ONLY
#ifdef RUN_SELECTED_TESTS_ONLY
#define SELECTION defined
#else
#define SELECTION(x) 1
#endif
#define TEST_1
//#define TEST_2
#include <stdio.h>
int main()
{
#if SELECTION(TEST_1)
printf("Test 1\n");
#endif
#if SELECTION(TEST_2)
printf("Test 2\n");
#endif
return 0;
}
Output:
Test 1
What you have invokes undefined behaviour. C standard says that the defined preprocessor operator may not appear as a result of replacement.
C11 draft, 6.10.1 Conditional inclusion
4 Prior to evaluation, macro invocations in the list of preprocessing
tokens that will become the controlling constant expression are
replaced (except for those macro names modified by the defined unary
operator), just as in normal text. If the token defined is generated
as a result of this replacement process or use of the defined unary
operator does not match one of the two specified forms prior to macro
replacement, the behavior is undefined. After all replacements due to
macro expansion and the defined unary operator have been performed,
all remaining identifiers (including those lexically identical to
keywords) are replaced with the pp-number 0, and then each
preprocessing token is converted into a token.
If you can't perform same check at run-time, you could do:
#define RUN_SELECTED_TESTS_ONLY
#define TEST_1
#if ((!defined (RUN_SELECTED_TESTS_ONLY)) || (defined (TEST_1)))
//code of test 1
#endif
Basically performing the "selection" yourself.
The error you get means: An identifier must follow the preprocessor keyword. (from MSDN).
It doesn't work because you cannot you defined() 2 times in your macro SELECTION(x).
What you can do instead is something like:
#define SELECTION(x) (!RUN_SELECTED_TESTS_ONLY || x)
#define RUN_SELECTED_TESTS_ONLY 1
#define TEST_1 1
#define TEST_2 0
#if SELECTION(TEST_1)
//some code
#endif
int main() {
printf("%d\n", SELECTION(TEST_1));
printf("%d\n", SELECTION(TEST_2));
return 0;
}
I am programming in C using CodeBlocks in Windows with the MingGW compiler that comes bundled with the most recent version. I am trying to get some compiler directives to work to demonstrate conditional compilation.
Below is my code. However, it would seem code blocks or MinGW does not like the #elif parts. If I set my defined macro value DEBUG_MODE to either 3 or 2 neither of the #elif structures appear to work.
Also, codeblocks is greying out the code that falls inside both #elif structures. Have I miscomprehended something about these compiler directives, or is it that not all versions of C support #elif? I know I can solve if just by nesting #if and #else structures, but Id like to know if #elif should work this way. Code below.
Ok so initially I made a schoolboy error and got my conditional logic around the wrong way. I have fixed it now but for the sake of completeness here it is.
Amended code below Codeblocks now behaves as I expect, mostly. The code colouring is off but functionally as I would expect.
#include <stdio.h>
#include <stdlib.h>
#define DEBUG_MODE 3
char * trace;
char * traceDesc;
int main()
{
trace = "main method normal start";
traceDesc = "Main method runs the body of the program to demonstrate compiler directives #if and #elif ";
#if DEBUG_MODE <= 3
printf("Program Begun!\n");
#elif DEBUG_MODE <= 2
printf("trace message %s :", trace);
#elif DEBUG_MODE <= 1
printf("Description message %s :", traceDescr);
#endif
return 0;
}
If I set my defined macro value DEBUG_MODE to either 3 or 2 neither of
the #elif structures appear to work.
That's because you say:
#if DEBUG_MODE >= 1
...
#elif
The condition was true and none of the subsequent blocks would be executed.
Depending upon what you're trying to achieve, you might want to say:
#if DEBUG_MODE >= 1
...
#endif
#if DEBUG_MODE >= 2
...
#endif
#if DEBUG_MODE >= 3
...
#endif