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.
Related
I want to use a basic macro in C to access a certain Bit b in a char-Array (*char) Arr:
#define TstBit (Arr,b) ( Arr[b/8] & (1 << (b%8)) )
however upon usage like such:
int foo(const char *charArray) {
int readindex = 0;
[...]
if(TstBit(charArray,readIndex++)) {
I get an error on the line with the #define-Statement:
main.c | line 7 | error: 'Arr' undeclared (first use in this function)
I'm suspecting I'm either passing the arguments poorly when calling the Function or that the #define needs some more parentheses.
The space after TstBit seems to be the problem here. The pre-processor, unlike the C compiler, is a bit more fussy about spaces.
With your macro, what the pre-processor does is replace all occurrences of TstBit with (Arr,b) which is not your intention.
#define TstBit(Arr,b) ( Arr[b/8] & (1 << (b%8)) )
should work the way you want.
EDIT: Also note that there is a problem with the way you are trying to use this macro, as noted in this comment!
Macro arguments should ideally not have side-effects. If they do, you should take care that they do not lead to undefined or unintended behaviour.
I am trying to use #if macros by defining the type of operation to invoke the right code, So i made a very simple example similar to what I am trying to do:
#include <stdio.h>
enum{ADD,SUB,MUL};
#define operation ADD
int main()
{
int a = 4;
int b = 2;
int c;
#if (operation == ADD)
c = a+b;
#endif
#if (operation == SUB)
c = a-b;
#endif
#if (operation == MUL)
c = a*b;
#endif
printf("result = %i",c);
return 0;
}
But unfortunately that does not work I get the following result = 8... if I replace The operation with numbers it works fine .... But i want it to work as it is described above.
Any help
The preprocessor is a step that is (in a way) done before the actual compiler sees the code. Therefore it has no idea about enumerations or their values, as they are set during compilation which happens after preprocessing.
You simply can't use preprocessor conditional compilation using enumerations.
The preprocessor will always consider that as false:
#if IDENT == IDENT
It can only test for numeric values.
Simplify your code and feed it to the preprocessor:
enum {ADD,SUB,MUL};
#define operation ADD
int main()
{
(operation == ADD);
}
The result of the preprocessor output is:
enum {ADD,SUB,MUL};
int main()
{
(ADD == ADD);
}
As you see, the enumerate value hasn't been evaluated. In the #if statement, that expression is just seen as false.
So a workaround would be to replace your enumerate by a series of #define:
#define ADD 1
#define SUB 2
#define MUL 3
like this it works. Output of preprocessor output is now:
int main()
{
int a = 4;
int b = 2;
int c;
c = a+b;
# 28 "test.c"
printf("result = %i",c);
return 0;
}
the solution is:
either rely at 100% on the preprocessor (as the solution above suggests)
or rely at 100% on the compiler (use enums and real if statements)
As others have said, the preprocessor performs its transformations at a very early phase in compilation, before enum values are known. So you can't do this test in #if.
However, you can just use an ordinary if statement. Any decent compiler with optimization enabled will detect that you're comparing constants, perform the tests at compile time, and throw out the code that will never be executed. So you'll get the same result that you were trying to achieve with #if.
But i want it to work as it is described above.
You seem to mean that you want the preprocessor to recognize the enum constants as such, and to evaluate the == expressions in that light. I'm afraid you're out of luck.
The preprocessor knows nothing about enums. It operates on a mostly-raw stream of tokens and whitespace. When it evaluates a directive such as
#if (operation == SUB)
it first performs macro expansion to produce
#if (ADD == SUB)
. Then it must somehow convert the tokens ADD and SUB to numbers, but, again, it knows nothing about enums or the C significance of the preceding code. Its rule for interpreting such symbols as numbers is simple: it replaces each with 0. The result is that all three preprocessor conditionals in your code will always evaluate to true.
If you want the preprocessor to do this then you need to define the symbols to the preprocessor. Since you're not otherwise using the enum, you might as well just replace it altogether with
#define ADD 1
#define SUB 2
#define MUL 3
If you want the enum, too, then just use different symbols with the preprocessor than you use for the enum constants. You can use the same or different values, as you like, because never the twain shall meet.
Another solution would be to have the enum in an included header file.
I read Xen source code and saw something like this:
#define is_domain_direct_mapped(d) ((void)(d), 0)
is_domain_direct_mapped is then used in a if statement as follows (d is a pointer to a struct variable):
if( is_domain_direct_mapped(d) ) {...}
So after compiler replaces is_domain_direct_mapped with its definition, we have something like:
if( ((void)(d), 0) ) {...}
The above if statement is very weird to me. This is the first time I see this kind of statement. How is it supposed to work?
It’s meant to always produce 0 but also evaluate d, in case it’s something with side-effects like p++.
As for why you would want to always produce 0: the implementation is different on ARM.
#define is_domain_direct_mapped(d) ((d) == hardware_domain && dom0_11_mapping)
Notice how d is evaluated exactly once here too.
Some discussion from when this was first introduced as confirmation – Re: [Xen-devel] [PATCH v3 1/3] xen/x86: introduce is_domain_direct_mapped(d) as (0) on x86:
When I've implemented this defined in common/memory.c, Jan told me to
use [1]:
#define is_domain_is_direct_mapped(d) ((void)(d), 0)
I suspect you want the same things here.
referencing Re: [v4] xen/arm: Allow balooning working with 1:1 memory mapping:
And you'll want to make sure (even if unlikely to be needed in
practice) that you evaluate the macro argument exactly once in both
flavors, i.e. in the case here
#define is_domain_direct_mapped(d) ((void)(d), 0)
This is the comma operator.
The left member (in your case d) is evaluated for its side effects and then discarded. The right member (0) gives the result.
I used this macro:
#define ISALPHA(text[i]) ('a'<=a && a<= 'z')|| ('A'<=a && a<= 'Z')? ("alpha"):("not alpha")
It gives this error: [Error] "[" may not appear in macro parameter list.
How to give an array value as a parameter in macros in C?
There are multiple bugs in your code, but the answer to the headline question is that you use a plain name in the macro argument list:
#define ISALPHA(c) ((('a' <= (c) && (c) <= 'z') || \
('A' <= (c) && (c) <= 'Z')) ? "alpha" : "not alpha")
You then invoke the macro on array elements using:
ISALPHA(text[i])
Note the extensive use of parentheses in the macro to avoid problems with odd-ball macro arguments.
Much better than all that testing, though, would be to use the standard (locale-sensitive) isalpha() macro from <ctype.h>:
#define ISALPHA(c) (isalpha(c) ? "alpha" : "not alpha")
Bugs in your version include:
Using text[i] instead of a in the macro arguments.
Not enclosing uses of a in parentheses.
Not enclosing the whole macro in parentheses.
(Minor) The test for whether a character is alphabetic is inaccurate for some code sets, such as EBCDIC used on IBM mainframes.
Enclosing the strings in parentheses was unnecessary, but was not going to cause any trouble.
My choice to use c as a mnemonic for 'character' is stylistic or personal preference; using a consistently (for 'alphabetic', presumably) would be fine too.
Why don't you use isalpha declared in ctype.h. It's much more safer than using macros. Don't get me wrong, macros are fine tools, provided that you know what you are doing but often enough you can end up with undefined behaviour and you don't realize it.
I've seen things like this (in 3rd party libraries)
#define min(x,y) ((x)<(y)?(x):(y))
that seems OK, but it's not. Later when you don't think what you are doing, you could do something like this:
int something(int x, int y)
{
return min(x++, y);
}
which expands to
int something(int x, int y)
{
return ((x++)<(y)?(x++):(y));
}
and yields undefined behaviour.
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...