C macro and makefile and expressions not work as expected - c

In my C code, I need to check my kernel version and act according to it.
In the makefile I have the following:
KERNEL_MAJOR :=$(word 1, $(subst ., ,$(KERNEL_HEADERS)))
KERNEL_MINOR :=$(word 2, $(subst ., ,$(KERNEL_HEADERS)))
KERNEL_MICRO :=$(word 1, $(subst -, ,$(word 3, $(subst ., ,$(KERNEL_HEADERS)))))
KERNEL_PATCH_LEVEL :=$(word 1, $(subst ., ,$(word 2, $(subst -, ,$(KERNEL_HEADERS)))))
KARGS := KCPPFLAGS="-DKERNEL_MAJOR=$(KERNEL_MAJOR) -DKERNEL_MINOR=$(KERNEL_MINOR) -DKERNEL_MICRO=$(KERNEL_MICRO) -DKERNEL_PATCH_LEVEL=$(KERNEL_PATCH_LEVEL)"
Samples:
3.0.101-0.47.71-default looks like:
KCPPFLAGS="-DKERNEL_MAJOR=3 -DKERNEL_MINOR=0 -DKERNEL_MICRO=101 -DKERNEL_PATCH_LEVEL=0"
4.1.21.x86_64.1 (notice KERNEL_PATCH_LEVEL):
KCPPFLAGS="-DKERNEL_MAJOR=4 -DKERNEL_MINOR=1 -DKERNEL_MICRO=21 -DKERNEL_PATCH_LEVEL="
I have macro in my code to check if kernel is 3.0.101.0 or 3.0.76.0:
#if defined(KERNEL_MAJOR) && defined(KERNEL_MINOR) && defined(KERNEL_MICRO) && defined(KERNEL_PATCH_LEVEL) && \
(KERNEL_VERSION(KERNEL_MAJOR,KERNEL_MINOR,KERNEL_MICRO) == KERNEL_VERSION(3,0,101) || KERNEL_VERSION(KERNEL_MAJOR,KERNEL_MINOR,KERNEL_MICRO) == KERNEL_VERSION(3,0,76)) \
&& (KERNEL_PATCH_LEVEL == 0)
There are 3 && boolean expressions, if expression #1 is ok, then i want to continue to expression #2, if expression #2 continue, i will continue to expression #3.
When i try to compile (make..) on kernel version 4.1.21.x86_64.1 i receive:
error: operator '==' has no left operand
This is because -DKERNEL_PATCH_LEVEL=" - see the output.
I would expect the make to prevent me from getting to that && condition since expression #2 has failed (3.0.101 or 3.0.76)

If you read: https://gcc.gnu.org/onlinedocs/gcc-3.0.2/cpp_4.html, you will find:
The `#if' directive allows you to test the value of an arithmetic expression, rather than the mere existence of one macro. Its syntax is
#if expression ...
expression is a C expression of integer type, subject to stringent restrictions. It may contain:
...
Macros. All macros in the expression are expanded before actual computation of the expression's value begins.
Identifiers that are not macros, which are all considered to be the number zero. ...
So if you had:
#if defined(FOO) && FOO == 1
And then didn't define foo, it would resolve the expression to:
0 && 0 == 1
which would then resolve to #if 0, which is valid. However, if you defined FOO to be blank, then it would resolve to:
1 && == 1
The precompiler would then try to parse the expression, and get a syntax error, and fail. Despite several comments that seem to be out on the web, the precompiler does not short-circuit the parsing of the expression, just the evaluation of the expression.
If you wanted to get around this, you can use some macro trickery as follows:
#define COMBINE1(W,Y,Z) W##Y##Z
#define COMBINE(W,Y,Z) COMBINE1(W,Y,Z)
#define ISEMPTY(val) COMBINE(val,4,val) == 4
#if defined FOO
#if ISEMPTY(FOO)
#pragma message "FOO DEFINED AS EMPTY"
#else
#pragma message "FOO DEFINED (NOT EMPTY)"
#endif
#else
#pragma message "FOO NOT DEFINED"
#endif
which gives:
~/sandbox/tst6> gcc tst2.c
tst2.c:12: note: #pragma message: FOO NOT DEFINED
~/sandbox/tst6> gcc tst2.c -DFOO=
tst2.c:7: note: #pragma message: FOO DEFINED AS EMPTY
~/sandbox/tst6> gcc tst2.c -DFOO=1
tst2.c:9: note: #pragma message: FOO DEFINED (NOT EMPTY)

You are right in believing that the C preprocessor, like the C compiler,
performs short-circuit evaluation of &&- and ||-expressions.
But you are wrong in believing the preprocessor, unlike the compiler,
can perform "short-circuit" evaluation of nonsensical token sequences,
provided that the nonsense is in one of the contexts:
TRUE || [nonsense]
or
FALSE && [nonsense]
Just like the compiler, any sequence the preprocessor can evaluate as an
expression, short-circuiting or not, must be a (well-formed) expression,
which
FALSE && ( == 0)
is not.

All the #if conditions pass because KERNEL_PATCH_LEVEL is defined. It's just defined as an empty string. -DKERNEL_PATCH_LEVEL= is equivalent to
#define KERNEL_PATCH_LEVEL
Which, of course, will pass an #if (defined) test.
It's somewhat difficult to test if a macro is empty. It might be easier to modify your makefile to define KERNEL_PATCH_LEVEL as some special value (like 0 or -1) if it isn't present in the version string.

Related

Variables conflict between Makefile and C code

In my C Makefile I have the following lines:
ifeq ($(VERBOSE_PRINT), TRUE)
CFLAGS += -D TRUE
else
CFLAGS += -D FALSE
endif
As you can tell by it's name, this flag indicated whether I should print debug statements or not.
In other place at my C code, I'm defining TRUE and FALSE with
#define FALSE 0
#define TRUE !FALSE
Then when I'm trying to compile my code, I get the following error:
types.h:6:0: error: "FALSE" redefined [-Werror]
#define FALSE 0
<command-line>:0:0: note: this is the location of the previous definition
If I delete the definition of TRUE and FALSE from my C code, my program get's crazy.
What's going on and how can I solve this conflict?
Thanks ahead.
You can't use the same name for two different incompatible things, so you'll need to change one of them. Most likely you want to change your Makefile, since what you have makes no sense. Something like:
ifeq ($(VERBOSE_PRINT), TRUE)
CFLAGS += -DDEBUG=1
else
CFLAGS += -DDEBUG=0
endif
Then in your C code you can have
#if DEBUG
printf( ... debugging messages ... )
#endif
On the compiler command line, -DXYZ is equivalent to -DXYZ=1 (POSIX c99). This means that with -DFALSE on the command line, you've got both #define FALSE 1 and #define FALSE 0, which is a non-benign redefinition. Benign redefinition of a macro is OK (meaning that the sequence of replacement tokens is the same in both the current and new definition — see C11 §6.10.3 Macro replacement ¶1-2).
You need to use a different variable in your code to decide whether to do printing:
#ifdef VERBOSE_PRINT
printf("Debugging!\n");
#endif
You can then use -DVERBOSE_PRINT on the command line to enable printing and leave it out to disable it. Alternatively, you can use:
#if VERBOSE_PRINT
printf("Debugging!\n");
#endif
Then your makefile can contain:
ifeq ($(VERBOSE_PRINT), TRUE)
CFLAGS += -DVERBOSE_PRINT=TRUE
else
CFLAGS += -DVERBOSE_PRINT=FALSE
endif
This technique is less common. It will work as if you have #define VERBOSE_PRINT 0 if you don't specify a value on the compiler command line (C11 §6.10.1 Conditional inclusion ¶4).

What is Significance of _v(l) in the macro?

I am trying to understand the following macro from the following URL:
do { \
word _v(l) = vec_len (V); \
V = _vec_resize ((V), 1, (_v(l) + 1) * sizeof ((V)[0]), (H), (A)); \
(V)[_v(l)] = (E); \
} while (0)
what is the significance of _v(l)? Is it just a variable or something more?
The _v macro is defined in vec.h at line 207:
#define _v(var) _vec_##var
This prepends _vec_ before var. You can observe this by asking your favorite compiler to print the output of the preprocessor stage (-E flag for clang/gcc and /E for msvc).
#define _v(var) _vec_##var
word _v(l) = vec_len (V);
Is expanded into:
word _vec_l = vec_len (V);
It is a variable whose name is generated. The name probably includes the current line number to make it unique. Therefore using this macro twice in a line may or may not work.
To see what the macro expands to, run gcc -E to only preprocess the code but not compile it. Do a bit of research about this -E computer option, it is helpful in many similar cases as well.

Can the C preprocessor perform arithmetic and if so, how?

I'm currently writing code for a microcontroller; since the ATMega128 does not have a hardware multiplier or divider, these operations must be done in software and they take up a decent amount of cycles. However, for code portability and ease of use, I'd prefer not to hard-code precomputed values into my code So for instance, I have a number of tasks which are dependent on the system clock frequency. Currently I' running at 16MHz, but should I choose to lower that, say to reduce power consumption for battery applications, I'd like to change one line of code rather than many.
So with that said, can the C preprocessor compute arithmetic expressions and then "paste" the result into my code rather than "pasting" the original expression into the code? If so, how would I go about doing this? Are their compiler options and whatnot that I need to consider?
NOTE: The values I want to compute are constant values, so I see no reason why this would not be a feature.
This is one question:
Q1. Can the C preprocessor perform arithmetic?
And this is another:
Q2. Can the C preprocessor compute arithmetic expressions and then "paste"
the result into my code rather than "pasting" the original expression into the code?
The answer to Q1 is Yes. The answer to Q2 is No. Both facts can be illustrated
with the following file:
foo.c
#define EXPR ((1 + 2) * 3)
#if EXPR == 9
int nine = EXPR;
#else
int not_nine = EXPR;
#endif
If we pass this to the C preprocessor, either by cpp foo.c or
equivalently gcc -E foo.c, we see output like:
# 1 "foo.c"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 30 "/usr/include/stdc-predef.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/predefs.h" 1 3 4
# 31 "/usr/include/stdc-predef.h" 2 3 4
# 1 "<command-line>" 2
# 1 "foo.c"
int nine = ((1 + 2) * 3);
The fact that the preprocessor retains the line defining int nine and
has dropped the line defining not_nine shows us that it has correctly performed
the arithmetic required to evaluate #if EXPR == 9.
The fact that the preprocessed text of the definition is int nine = ((1 + 2) * 3);
shows us that the #define directive causes the preprocessor to replace
EXPR with its definition ((1 + 2) * 3), and not with the arithmetic value
of its definition, 9.
Does the C preprocessor have any directive besides #define which has the second
effect? No.
But this does not of course imply that the definition of int nine must entail a
runtime calculation, because the compiler will almost certainly evaluate
the arithmetic expression ((1 + 2) * 3) at compiletime and replace it with
the constant 9.
We can see how the compiler has translated the source file by examining the
compiled object file. Most toolchains will provide something like GNU binutils
objdump to assist with this. If I compile foo.c with gcc:
gcc -c -o foo.o foo.c
and then invoke:
objdump -s foo.o
to see the full contents of foo.o, I get:
foo.o: file format elf64-x86-64
Contents of section .data:
0000 09000000 ....
Contents of section .comment:
0000 00474343 3a202855 62756e74 752f4c69 .GCC: (Ubuntu/Li
0010 6e61726f 20342e38 2e312d31 30756275 naro 4.8.1-10ubu
0020 6e747539 2920342e 382e3100 ntu9) 4.8.1.
And there is the hoped-for 9 hard-coded in the .data section.
Note that the preprocessor's arithmetic capabilities are restricted to integer arithmetic
It can, but is unnecessary: you don't actually need to involve the preprocessor unless you actually want to generate new identifiers that involve numbers in some way (e.g. stuff like func1, func2).
Expressions like 1 + 2 * 3, where all elements are compile-time constant integer values, will be replaced with the single result at compile-time (this is more or less demanded by the C standard, so it's not "really" an optimisation). So just #define constants where you need to name a value that can be changed from one place, make sure the expression doesn't involve any runtime variables, and unless your compiler is intentionally getting in your way you should have no runtime operations to worry about.
Yes you can do arithmetic using the preprocessor, but it takes a lot of work. Reading this page here, shows how to create an increment counter, and a while loop. So with that you could create addition:
#define ADD_PRED(x, y) y
#define ADD_OP(x, y) INC(x), DEC(y)
#define ADD(x, y) WHILE(ADD_PRED, ADD_OP, x, y)
EVAL(ADD(1, 2)) // Expands to 3
So reusing the ADD macro you can then create a MUL macro something like this:
#define MUL_PRED(r, x, y) y
#define MUL_OP(r, x, y) ADD(r, x), x, DEC(y)
#define MUL_FINAL(r, x, y) r
#define MUL(x, y) MUL_FINAL(WHILE(MUL_PRED, MUL_OP, 0, x, y))
EVAL(MUL(2, 3)) // Expands to 6
Division and subtraction can be built in a similiar way.
I compiled a file containing the following lines using gcc -E.
#define MUL(A, B) ((A)*(B))
#define CONST_A 10
#define CONST_B 20
int foo()
{
return MUL(CONST_A, CONST_B);
}
The output was:
# 1 "test-96.c"
# 1 "<command-line>"
# 1 "test-96.c"
int foo()
{
return ((10)*(20));
}
That's just one data point for you.

gcc c error: expected ')' before numeric constant

Hi I have been trying to port LWIP to a new arm device. When compiling the code i get the error message:
"lwip/lwip-1.4.0/src/include/lwip/memp_std.h:35:23: error: expected ')' before numeric constant"
When I go to this file this and below this several similar macros is what I find on that line:
LWIP_MEMPOOL(RAW_PCB, MEMP_NUM_RAW_PCB, sizeof(struct raw_pcb), "RAW_PCB")
If I remove the need for this macro with a define to deactivate the RAW functionality the error moves to the next LWIP_MEMPOL() macro.
The define it seems to want to put a ')' in front of is defined as this:
#define MEMP_NUM_RAW_PCB 1
The RAW_PCB is not defined but is "combined with MEMP_" to create an element in an enum.
I have tried to complie the whole ting with the -E option to get human redable object files and see if i can find any open '(' around the areas where MEMP_RAW_PCB apears and the substitution of MEMP_NUM_RAW_PCB to 1 but I have not found any by manual inspection yet.
Are there any suggestions on what can be going on here or what more I can do or look for to find the cause of the error?
I should maybe add that so far I don't call on any of the LWIP code from main() or any of the functions used in main().
I solved it with:
#ifndef MEMP_STD_H_
#define MEMP_STD_H_
... // memp_std.h codes ...
#endif //#ifndef MEMP_STD_H_
The error suggests you have unbalanced parentheses. The code you have provided thus far does not indicate where this problem is, but since ) is expected, it probably means the error is actually in the lines of code preceding the one you have shown.
Examine the code preceding the line you have shown (perhaps after using gcc -E) to check to see if all the parentheses are balanced.
If you're defining it with the dash-D option, it will generate the 1 by default, e.g.:
gcc -D 'MAX(A,B) ((A) < (B)? (B) : (A))' ...
Generates:
#define MAX(A,B) ((A) < (B)? (B) : (A)) 1
And you get the error: expected ‘)’ before numeric constant message at the line where the substitution occurs because of that trailing 1, e.g.:
int maxval = MAX(i,j);
// generates: int maxval = ((i) < (j)? (j) : (i)) 1;
Conversely, if you use the assignment operator to explicitly define the value, it will generate it the way you expected. E.g.:
int maxval = MAX(i,j);
// generates: int maxval = ((i) < (j)? (j) : (i));

Using __VA_ARGS for printf

I am trying to write #define for ASSERT() using __VA_ARGS.
(This code is for an embedded processor which doesn't support all libc functions).
My source code is like this:
ASSERT(msg == NULL)
ASSERT in header file:
#define ASSERT(...) if(__VA_ARGS__) { printf("[ASSERT ERROR]" __VA_ARGS__ "\n"); }
The preprocessor output is like this, which results compilation error.
if(msg == NULL) { printf("[ASSERT ERROR]" msg == NULL "\n"); }
How do I fix the #define to get rid of compilation errors while keeping the code logically correct?
There's no reason for this to be a variadic macro, at least not with telling us more information about what exactly you're trying to do. A simple one-argument macro using the stringizing operator # will do the trick nicely:
#define ASSERT(x) if(x); else printf("[ASSERT ERROR] " #x "\n")
Also note that I omitted the semicolon at the end and wrote it as if(x); else instead of if(!(x)), so that all of the following code fragments compile correctly as you'd expect, or produce a compiler error as you'd expect:
// #1 - this must be an error, no semicolon
ASSERT(x)
// #2 - this must also be an error
ASSERT(x)
else
/*stuff*/ ;
// #3 - the else must go with the first if, not the inner if inside the macro
// expansion
if (x)
ASSERT(y);
else
/*stuff*/ ;
Your original macro definition fails test #3 above.

Resources