This question already has answers here:
Why can't I use sizeof in a preprocessor condition?
(2 answers)
Closed 9 years ago.
I have this:
#if sizeof(int)
#error Can't use sizeof in a #if
#endif
I get this compiler error:
missing binary operator before token "("
Why can't I use the sizeof operator here?
Because sizeof() is calculated after the preprocessor is run, so the information is not available for #if.
C compilers are logically split into two phases, even if most modern compilers don't separate them. First, the source is preprocessed. This involves working out and substituting all the preprocessor conditionals (#if, #define, replacing defined words with their replacements). The source is then passed, processed, to the compiler itself. The preprocessor is only minimally aware of the structure of C, it has no type knowledge, so it can't handle compiler-level constructs like sizeof().
Because you can only use literal constants in a preprocessor directive. Besides, sizeof(int) is always larger than 0, so I believe this #if would be true all the time anyway.
Consider:
#if sizeof(MyClass) > 3
#define MY_CONSTRAINT 2
#endif
class MyClass
{
#if MY_CONSTRAINT == 3
int myMember = 3;
#endif
};
Now, this is prolly not written in the correct syntax as it's been a while since the last time I did C++, but the point still stands :)
just use ordinary if-else
if (sizeof(x)==2) {...}
else if (sizeof(x)==4) {...}
else {...}
and compiler will optimize it in compile time...
Related
I saw the following in a .h-file for the cc2640 mcu:
#define ADC_STATUS_SUCCESS (0)
From my C knowledge, the compiler is told to put the value of ADC_STATUS_SUCCESS everywhere it occurs, that is (0). But what is the difference in putting just 0?
what is the difference in putting just 0?
None, if you don't write crazy code. It is common to use parentheses for macros that contain expressions to avoid unexpected errors related to operator precedence and similar stuff when using them. In this case though, defining something as 0 or as (0) is the same if it's used in expressions.
What do I mean by "crazy code"? Well, the only difference between the two can be seen in something like the following:
void func(int x) { /* ... */ };
#define ADC_STATUS_SUCCESS 0
func ADC_STATUS_SUCCESS; // INVALID
#define ADC_STATUS_SUCCESS (0)
func ADC_STATUS_SUCCESS; // VALID (for the love of God NEVER do this)
I highly doubt this is the case though, nobody in their right mind would write such an abomination. That define is most likely out of habit.
i'm trying to define the following macro:
#define UTF8_2B(c) if((0xc0 & c) == 0xc0){return 1;}
But i'm met with the error:
expected expression before ‘if’
The macro is called like so:
int i = UTF8_2B(c);
Where c is an unsigned char read from a file.
Why does this happen? Can you not use if else statements in macros?
Also, I've read that it's not a good idea to use semicolon in your macros, but i didn't understand why.
I'm new to c so the more thorough the answer the better.
C (and C++) preprocessor macros are essentially "copy-paste" with argument substitution. So your code becomes:
int i = if((0xc0 & c) == 0xc0){return 1;}
And this is invalid syntax.
You're assigning the result of your macro to a variable. You cannot do that with the current macro (return returns from the current function, and doesn't return something to be assigned to i: so not what you want).
If you're using gcc, you can view what your pre-processed code looks like with the -E command line.
So you can use if in macros, but not in macros that are used like functions, which are supposed to return a value.
Moreover:
if c is a complex expression, operator precedence could make the macro generate wrong code
the macro should provide a way to require semicolon, so IDEs and human readers see that as a normal function
I'd propose a simple test instead (which yields 1 if true, 0 otherwise), which meets the "need semicolon" standard and is safe to use with a complex c expression:
#define UTF8_2B(c) ((0xc0 & (c)) == 0xc0)
The ternary operator exists for this purpose. Assuming you want 1 if true and 0 if false, the correct macro is:
#define UTF8_2B(c) (((c) & 0xC0) == 0xC0 ? 1 : 0)
Now you can assign the result. Using return in a macro will return from the enclosing function, not from the macro, and is almost always a bad idea.
I have read lots on stringizing macros, but I obviously don't quite understand. I wish to make a string where the argument to the macro needs to be evaluated first. Can someone please explain where I am going wrong, or perhaps how to do this better?
#define SDDISK 2 // Note defined in a library file elsewhere ie not a constant I know)
#define DRIVE_STR(d) #d ":/"
#define xDRIVE_STR(x) DRIVE_STR(x)
#define FILEPATH(f) xDRIVE_STR(SDDISK + '0') #f
const char file[] = FILEPATH(test.log);
void main(void)
{
DebugPrint(file);
}
The output is: "2 + '0':/test.log",
But I want "2:/test.log"
The C PREprocessor runs before the compiler ever sees the code.
This means that the equation will not be evaluated before it is stringified; instead, the preprocessor will just stringize the whole equation.
In your case just removing the +'0' will solve the problem as the value of SDDISK does not need casting to a char before it is stringified.
However, should you actually need to perform a calculation before stringizing you should either:
Use cpp's constexpr.
Complain to your compiler vendor that a constant expression was not optimized.
Use a preprocessor library to gain the wanted behaviour.
This question already has answers here:
C : #define usage [duplicate]
(3 answers)
Closed 7 years ago.
#include <stdio.h>
#define SQR(x) x*x
int main()
{
printf("%d",225/SQR(15));
return 0;
}
The output to this code is 225. I'm unable to understand as what really is happening here.
If I use #define SQR(x) (x*x) Then it works fine which i get as we are supposed to use parentheses if we have an expression with some operator.
But in the previous case I'm not clear as to what is really happening. Why is the answer 225?
#define macros aren't functions - they are just macros, text replacement. If you take the expression 225/SQR(15) and replace SQR with 15*15, you'll get 225/15*15, and since / and * have the save precedence and are left associative - 255/15*15 = 255.
Macros do substitution only(done before compilation of the code).
Therefore the following line
printf("%d",225/SQR(15));
after substitution will become:
printf("%d",225/15*15);
now this expression evaluates to 225 (basic maths : divide first -> 15*15, then multiply -> 225)
using brackets solves your problem(then it becomes 225/(15*15)).
:)
Notice the steps
1) 225/SQR(15)
2) 225/15*15
Division executed first due to precedence
3) 15*15
4) 225
See #define as a text replacement tool in a text editor; it works the same way (well, almost).
Here are two rules you might want to follow in order to avoid this kind of errors:
When working with macros, always use parentheses for each "variable" given to the macro and for the whole result.
Example:
#define MAX(a, b) ((a) > (b) ? (a) : (b))
When you have an unexpected behavior, use the command line tool cpp (c preprocessor) to see how the macro is actually interpreted.
Example:
$ cpp main.c
I'm using the variadic macro to simulate a default argument. I compile with -Wunused-value. Thus, I get the following warning:
warning: left-hand operand of comma expression has no effect
Is there a way to somehow fix this warning without having to remove -Wunused-value? or do I have to end up using #pragma GCC diagnostic ignored "-Wunused-value"?
#include <stdio.h>
#define SUM(a,...) sum( a, (5, ##__VA_ARGS__) )
int sum (int a, int b)
{
return a + b;
}
int main()
{
printf("%d\n", SUM( 3, 7 ) );
printf("%d\n", SUM( 3 ) );
}
The ## construct that you are using is a gcc speciality and not portable. Don't use it, there are other ways.
The following should do what you expect
#define SUM2(A, B, ...) sum((A), (B))
#define SUM1(...) SUM2(__VA_ARGS__)
#define SUM(...) SUM1(__VA_ARGS__, 5, 0)
Such games with macro default arguments are frowned upon by many, because they may make the code more difficult to read.
For the moment I'd suggest that you don't use such constructs in your programs. You should perhaps learn more of the basics before you go into such esoteric stuff.
Also your idea to want to silence the compiler is really a bad one. The compiler is there to help you, listen to him. In the contrary, raise the warning level to a maximum and improve your code until it compiles without any warning.
Jens Gustedt proposed a very good problem-specific portable solution. I didn't know, ,##__VA_ARGS__ is a GCC extension (maybe Clang too?). There are however GCC-specific solutions for the authors initial intension.
As a problem-specific and very GCC-specific solution, you can use _Pragma("GCC diagnostic ignored \"-Wunused-value\"") and delimit it around the macro expansion. This will keep the comfort of readability. This does not work everywhere. It mainly fails within static initializer lists placed outside of functions where those pragmas can't be applied. I really was looking for a solution within such initializer lists because I couldn't find any which hides the warning pragmas from the reader. Other than that, for a function call like sum() for example - which I suppose to be only valid in a function body itself -, you can use it:
#define SUM(a,...) ({\
_Pragma("GCC diagnostic push")\
_Pragma("GCC diagnostic ignored \"-Wunused-value\"")\
sum( a, (5, ##__VA_ARGS__) );\
_Pragma("GCC diagnostic pop")\
})
Remember, you can only use it in function bodies and where an expression is expected. The warning will remain turned on after the macro expansion.
But I found a general solution! Conditional-macro-expansion is possible with the ,##__VA_ARGS__ feature. It gives you the power of conditional expansion based on blankness of the argument.
This feature does not necessarily add substitution power to the preprocessor. If you use arguments which include commas like (<...>) for false or 0 and (<...>,<...>) for true or 1, you can achieve the same. But only the conditional comma allows you the comfort of expanding conditionally based on the blankness of an argument.
See: you might be able to write your code like SUM(A) expanding to sum((A),5) without ##__VA_ARGS__ but you might not be able to write SUM(,B) expanding to sum((somevalue),B) . But you can do that with ##__VA_ARGS__ .
Example:
#define _VADIC(...) , ##__VA_ARGS__
//expands to A if A is not blank else to __VA_ARGS__ as fallback value
#define TRY(A,B) _TRY0(_VADIC(A), B)
#define _TRY0(...) _TRY1(__VA_ARGS__) /*expand before call*/
#define _TRY1(A, B, ...) B
//expands to THEN if A is blank otherwise expands to blank
#define IF(A,THEN) _IF0(_VADIC(A),THEN)
#define _IF0(...) _IF1(__VA_ARGS__) /*expand before call*/
#define _IF1(A,B,...) __VA_ARGS__
//expands to ELSE if A is not blank otherwise expands to blank
#define IFNOT(A,ELSE) _IFNOT0(_VADIC(A),,ELSE)
#define _IFNOT0(...) _IFNOT1(__VA_ARGS__) /*expand before call*/
#define _IFNOT1(A,B,C,...) C
#define IF_ELSE(A, THEN, ELSE) IF(A,THEN)IFNOT(A,ELSE)
Without the conditional comma, you only can expand conditionally on the number of arguments or on predefined concatenations but this way, you can use ANY single undefined symbol as condition.
PS: What about loops? Macros in C are designed to be finite for faster compilation. You won't get infinite loops since the limit of loop cycles depends on the source code size. Limited loops is the only thing which hinders you from turing-completeness, but practical real-world computer science problems (different from embedded or operating systems) don't need infinite loops for calculations. They are all limited depending with the problem size. The turing machine also uses a finite alphabet of symbols. You could know the limit of loop cycles which are needed in the worst case and it is possible to create a functional loop (a "reduce" or "filter" macro) running on variable-length macro argument lists which can reformat the macro argument list and do magic. The only requirement is the comma. You can't iterate over elements without a comma in between.