Double evaluation within macro: a case of sizeof() to determine array's size passed as compound literal - c-preprocessor

C99 makes it possible to define arrays basically anywhere, as compound literals.
For example, given a trivial function sumf() that accepts an array of float as input, we would expect the prototype to be :
float sumf(const float* arrayf, size_t size);
This can then be used like that :
float total = sumf( (const float[]){ f1, f2, f3 }, 3 );
It's convenient because there is no need to declare a variable beforehand.
The syntax is slightly ugly, but this could be hidden behind a macro.
However, note the final 3. This is the size of the array. It is required so that sumf() knows where to stop. But as code ages and get refactored, it's also an easy source of errors, because now this second argument must be kept in sync with the first parameter definition. For example, adding f4 requires to update this value to 4, otherwise the function returns a wrong calculation (and there is no warning notifying this issue).
So it would be better to keep both in sync.
If it was an array which was declared through a variable, it would be easy.
We could have a macro, that simplifies the expression like this : float total = sumf( ARRAY(array_f) ); with just #define ARRAY(a) (a) , sizeof(a) / sizeof(*(a)). But then, array_f must be defined before calling the function, so it's not longer a compound literal.
Since it's a compound literal, it has no name, so it can't be referenced. Hence I could not find any better way than to repeat the compound literal in both parameters.
#define LIST_F(...) (const float*)( __VA_ARGS__) , sizeof((const float*)( __VA_ARGS__)) / sizeof(float)
float total = sumf ( LIST_F( f1, f2, f3 ) );
and this would work. Adding an f4 into the list would automatically update the size argument to correct size.
However, this all works fine as long as all members are variables. But what about cases where it's a function ? Would the function be invoked twice ?
Say for example : float total = sumf ( LIST_F( v1, f2() ) );, will f2() be invoked twice? This is unclear to me as f2() is mentioned within sizeof(), so it could, in theory, know the return type size without actually invoking f2(). But I'm unsure what the standard says about that. Is there a guarantee ? Is it implementation dependent ?

will f2() be invoked twice?
No, sizeof is not evaluated (unless it's a variable length array, but it's not).
what the standard says about that. Is there a guarantee ?
From C11 6.5.3.4p2:
The sizeof operator yields the size (in bytes) of its operand, [...] If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.
Is it implementation dependent ?
No, it should be always fine.
Note that your other macro uses (const float*)(__VA_ARGS__), that will not work - the syntax is (float[]){ stuff }. Anyway, I would just do one macro, why two, too much typing. Just:
#define SUMF_ARRAY(...) \
sumf( \
(const float[]){__VA_ARGS__}, \
sizeof((const float[]){__VA_ARGS__}) / sizeof(float))
float total = SUMF_ARRAY(f1(), f2(), f3());

Related

Implementing std::bit_cast equivalent in C

Is it possible to implement something similar to C++20's std::bit_cast in C? It would be a lot more convenient than using union or casting pointers to different types and dereferencing.
If you had a bit_cast, then implementing some floating point functions would be easier:
float Q_rsqrt( float number )
{
int i = 0x5f3759df - ( bit_cast(int, number) >> 1 );
float y = bit_cast(float, i);
y = y * ( 1.5f - ( number * 0.5f * y * y ) );
y = y * ( 1.5f - ( number * 0.5f * y * y ) );
return y;
}
See also Fast inverse square root
The naive solution is:
#define bit_cast(T, ...) (*(T*) &(__VA_ARGS__))
But it has major problems:
it is undefined behavior because it violates strict aliasing
it doesn't work for bit-casting rvalues because we are taking the address of the second operand directly
it doesn't make sure that the operands have the same size
Can we implement a bit_cast without these issues?
It is possible in non-standard standard C, thanks to typeof. typeof is also a further proposed feature for C23, so it may become possible in standard C23. One of the solutions below makes some sacrifices which allow C99 compliance.
Implementation Using union
Let's look at how the approach using union works first:
#define bit_cast(T, ...) \
((union{typeof(T) a; typeof(__VA_ARGS__) b;}) {.b=(__VA_ARGS__)}.a)
We are creating a compound literal from an anonymous union made of T and whatever type the given expression has. We initialize this literal to .b= ... using designated initializers and then access the .a member of type T.
The typeof(T) is necessary if we want to pun function pointers, arrays, etc., due to C's type syntax.
Implementation using memcpy
This implementation is slightly longer, but has the advantage of relying only on C99, and can even work without the use of typeof:
#define bit_cast(T, ...) \
(*(typeof(T)*) memcpy(&(T){0}, &(typeof(__VA_ARGS__)) {(__VA_ARGS__)}, sizeof(T)))
We are copying from one compound literal to another and then accessing the destination's value:
the source literal is a copy of our input expression, which allows us to take its address, even for bit_cast(float, 123) where 123 is an rvalue
the destination is a zero-initialized literal of type T
memcpy returns the destination operand, so we can cast the result to typeof(T)* and then dereference that pointer.
We can completely eliminate typeof here and make this C99-compliant, but there are downsides:
#define bit_cast(T, ...) \
(*((T*) memcpy(&(T){0}, &(__VA_ARGS__), sizeof(T))))
We are now taking the address of the expression directly, so we can't use bit_cast on rvalues anymore. We are using T* without typeof, so we can no longer convert to function pointers, arrays, etc.
Implementing Size Checking (since C11)
As for the last issue, which is that we don't verify that both operands have the same size: We can use _Static_assert (since C11) to make sure of that. Unfortunately, _Static_assert is a declaration, not an expression, so we have to wrap it up:
#define static_assert_expr(...) \
((void) (struct{_Static_assert(__VA_ARGS__); int _;}) {0})
We are creating a compound literal that contains the assertion and discarding the expression.
We can easily integrate this in the previous two implementations using the comma operator:
#define bit_cast_memcpy(T, ...) ( \
static_assert_expr(sizeof(T) == sizeof(__VA_ARGS__), "operands must have the same size"), \
(*(typeof(T)*) memcpy(&(T){0}, &(typeof(__VA_ARGS__)) {(__VA_ARGS__)}, sizeof(T))) \
)
#define bit_cast_union(T, ...) ( \
static_assert_expr(sizeof(T) == sizeof(__VA_ARGS__), "operands must have the same size"), \
((union{typeof(T) a; typeof(__VA_ARGS__) b;}) {.b=(__VA_ARGS__)}.a) \
)
Known and Unfixable Issues
Because of how macros work, we can not use this if the punned type contains a comma:
bit_cast(int[0,1], x)
This doesn't work because macros ignore square brackets and the 1] would not be considered part of the type, but would go into __VA_ARGS__.

C: Reasoning for the compilation error while using linker file variables

Code Snippet from a ARM linker file:
....
__RW_START_ = .;
...
...
...
...
__RW_END_ = .;
__RW_SIZE__ = __RW_END__ - __RW_START_;
....
Referring the variables RW_START, RW_END & RW_SIZE from above linker in the below C source file.
Code Snippet from a C source file:
....
#define _MAP_REGION_FULL_SPEC(_pa, _va, _sz, _attr, _gr) \
{ \
.base_pa = (_pa), \
.base_va = (_va), \
.size = (_sz), \
.attr = (_attr), \
.granularity = (_gr), \
}
#define MAP_REGION(_pa, _va, _sz, _attr) \
_MAP_REGION_FULL_SPEC(_pa, _va, _sz, _attr, REGION_DEFAULT_GRANULARITY)
#define MAP_REGION_FLAT(adr, sz, attr) MAP_REGION(adr, adr, sz, attr)
extern unsigned long __RW_START__;
extern unsigned long __RW_END__;
extern unsigned long __RW_SIZE__;
#define BL2_EL3_RW_START (const unsigned long)(&__RW_START__)
#define BL2_EL3_RW_SIZE (const unsigned long) ((&__RW_END__) - (&__RW_START__))
//#define BL2_EL3_RW_SIZE (const unsigned long) (&__RW_SIZE__)
#define LS_BL2_EL3_RW_MEM MAP_REGION_FLAT(BL2_EL3_RW_START, \
BL2_EL3_RW_SIZE, \
MT_DEVICE | MT_RW | MT_SECURE)
...
...
typedef struct mmap_region {
unsigned long long base_pa;
uintptr_t base_va;
size_t size;
mmap_attr_t attr;
size_t granularity;
} mmap_region_t;
const mmap_region_t plat_ls_mmap = LS_BL2_EL3_RW_MEM; //compiler error
...
...
Question: Explain the below two observation:
ARM Compiler gives following error when BL2_EL3_RW_SIZE is defined as above:
error: initializer element is not constant
.size = (_sz), \
^
ARM Compiler gives no error when BL2_EL3_RW_SIZE is defined as above(in commented lines).
Well, for the first error you should have to post the exact argument passed to the macro at invocation, as probably you have passed a variable name as parameter and that requires code (executable) to retrieve the variable value and put it on the right place (this is what is not constant). By expanding the macros as used (you don't post any actual macro expansion, only the macro definitions) the expansion of LS_BL2_EL3_RW_MEM gives:
MAP_REGION_FLAT(BL2_EL3_RW_START, \
BL2_EL3_RW_SIZE, \
MT_DEVICE | MT_RW | MT_SECURE)
where the second parameter is a macro invocation that expands to
(const unsigned long) ((&__RW_END__) - (&__RW_START__))
which is not a constant expression, as it involves the evaluation of two long variable addresses (namely __RW_END__ and __RW_START__) and compute their difference (as a C expression). The C language only considers the & address operator as being able to construct a constant expression when the variable is global (as this is the case) as the addresses of dynamic variables and pointer dereferences are dynamic and non constant in nature. The problem here is that you have to substract the addresses of the two variables to form the initialization value, and that requires code (so no data inline can be used to initialize, only the calculation proper) cannot initialise a struct field with a non-constant expression. You have to use an assignment for that.
Even if having the cast to (const unsigned long), that doesn't imply the expression is a constant expression. What the const means here is that herein on, the expression value cannot be further modified, it should be considered a constant.... but that doesn't mean you are parsing a constant expression. A constant expression is one that can be solved at compile time (and indeed, an expression that depends on the value of two linker variables, cannot be determined at compile time, you'll agree with me on this, for sure) And in the present case, it is indeed true (that the expression is not constant) for the addresses of those variables, as the position of the two variables is not known until the linker has placed all segments inline and determines (in the second pass) the offset values and addresses of everything.
Further, even the value of __RW_SIZE__ (which is the thing computed in the macro) is not a constant expression. It is computed at link time, and so you cannot determine the result value until you have finished compiling. The macro purpose is only for the case you don't have access to the variable.
Finally, the last case (the compiler not giving a complaint when the value used is the address of the __RW_SIZE__ variable) is that then, the expression is a constant... the constant is precisely the address of a global variable. This is determined at link time, but with a constant, fixed value, that has not to be calculated. But you have to think on one thing... the value of __RW_SIZE__ is the value you need, and not it's address, so if you initialise the struct field with the address of __RW_SIZE__, then you are making a mistake, as the address and the value of __RW_SIZE__ are two different things (indeed, if you substitute the value of __RW_SIZE__ into the initializer, you'll see the same error as in the first case, because the contents of __RW_SIZE__ are not know at compilation time.)
WHAT THE HELL IS A CONSTANT EXPRESSION
Constant expression (compile time) is an expression that can fully be computed at compile time (not something labeled with a const keyword) The compiler allows you to put an expression to facilitate things, but the compilation of such an initializer is always a constan value. This means that, if you put something like:
int a = 3 + 2;
the compiler will reserve space for a variable and fill the .data segment with four bytes and the constant 5 on it (the compiler calculates the value, instead of generating code to calculate it)
This makes things like
#define RAD_TO_DEGREES (180.0 / MATH_PI)
to be possible initializers, as the compiler can calculate the division and initialize the variable RAD_TO_DEGREES to the proper constant.
But if you put something like:
double SIN_OF_30 = cos(30.0 / RAD_TO_DEGREES);
let's see what happens.... the compiler interprets the expression and calculates the argument to the sin function first. RAD_TO_DEGREES happens to be 57.2957795 which is known at compile time (be careful, it isn't if you have defined a variable with that value and initialised with it, and you use the variable in the calculation, as the variable has only that value is something that only you know, the compiler doesn't). This leads to the argument value of 0.5235988, but then comes the problem. The sin(3) function is a mathematical function that comes from the mathematical standard library, so the compiler has to execute it to compute the final value of 0.5, so this is NOT A CONSTANT EXPRESSION, even when the final variable has defined as const. Only if you avoid to pass through sin() you have a constant expression. So you can use
double SIN_OF_30 = 0.5;
double COS_OF_30 = 0.8660;
but not
double SIN_OF_30 = sin(30.0 / RAD_TO_DEG);
double COS_OF_30 = cos(30.0 / RAD_TO_DEG);
for automatic variables, this doesn't hold, as the initialization is done at run time, so the compiler generates the neccessary code to initialize them
int main()
{
double SIN_OF_30 = sin(30.0 / RAD_TO_DEG);
double COS_OF_30 = cos(30.0 / RAD_TO_DEG);
}
is perfectly valid. Each time you enter the main function, two variables are created in the stack, and initialised with the values result of the expressions you put there (which don't have to be constant, compile-time expressions).
First of all, the problem you are having has nothing to do with linker file variables.
When you initialize a file-local variable, its initial value must be a constant expression. So your "observation 1" is perfectly logical. The main question is, why the second observation does not give an error.
The answer is relocation. The compiler is allowed to extend what "constant expression" means, and most compilers accept relocations as constant expressions.
Here is a little code snippet with comments:
// Note: "const" here means "read-only", not "constant expression"
const unsigned long var1, var2;
// This is not allowed, initializers must be constant expressions
unsigned long test1 = var1;
// This however is supported by compiler using relocation as a constant expression
unsigned long test2 = (unsigned long)&var1;
// This is supported by using relocation with addend
unsigned long test3 = (unsigned long)&var1 + 10;
// This is not supported by relocation - there is no relocation type that supports division with addend
unsigned long test4 = (unsigned long)&var1 / 10;
// This is not supported by relocation - addend itself cannot be relocation
unsigned long test5 = (unsigned long)&var1 + (unsigned long)&var2;
int main (int argc, char **argv)
{
// Yes, this is how we do it...
unsigned long test6 = (unsigned long)&var1 + (unsigned long)&var2;
return 0;
}
Now, to solve your initial problem - even though #define BL2_EL3_RW_SIZE (const unsigned long) (&__RW_SIZE__) compiles, doesn't mean it gives you the expected result. It only uses the address of the __RW_SIZE__ to initialize the struct member and the address of the __RW_SIZE__ is the same as the address of __RW_END__. You cannot get the value of linker variable from C code.
Only way you can achieve what you want is initialize the variable during run-time by using some init() function and doing plat_ls_mmap.size = &__RW_END__ - &__RW_START__;

Multiline macro function with "return" statement

I'm currently working on a project, and a particular part needs a multi-line macro function (a regular function won't work here as far as I know).
The goal is to make a stack manipulation macro, that pulls data of an arbitrary type off the stack (being the internal stack from a function call, not a high-level "stack" data type). If it were a function, it'd look like this:
type MY_MACRO_FUNC(void *ptr, type);
Where type is the type of data being pulled from the stack.
I currently have a working implementation of this for my platform (AVR):
#define MY_MACRO_FUNC(ptr, type) (*(type*)ptr); \
(ptr = /* Pointer arithmetic and other stuff here */)
This allows me to write something like:
int i = MY_MACRO_FUNC(ptr, int);
As you can see in the implementation, this works because the statement which assigns i is the first line in the macro: (*(type*)ptr).
However, what I'd really like is to be able to have a statement before this, to verify that ptr is a valid pointer before anything gets broken. But, this would cause the macro to be expanded with the int i = pointing to that pointer check. Is there any way to get around this issue in standard C? Thanks for any help!
As John Bollinger points out, macros expanding to multiple statements can have surprising results. A way to make several statements (and declarations!) a single statement is to wrap them into a block (surrounded by do … while(0), see for example here).
In this case, however, the macro should evaluate to something, so it must be an expression (and not a statement). Everything but declarations and iteration and jump statements (for, while, goto) can be transformed to an expression: Several expressions can be sequenced with the comma operator, if-else-clauses can be replaced by the conditional operator (?:).
Given that the original value of ptr can be recovered (I’ll assume "arithmetic and other stuff here" as adding 4 for the sake of having an example)
#define MY_MACRO_FUNC(ptr, type) \
( (ptr) && (uintptr_t)(ptr)%4 == 0 \
? (ptr) += 4 , *(type*)((ptr) - 4) \
: (abort() , (type){ 0 }) )
Note, that I put parentheses around ptr and around the whole expression, see e.g. here for an explanation.
The second and third operand of ?: must be of the same type, so I included (type){0} after the abort call. This expression is never evaluated. You just need some valid dummy object; here, type cannot be a function type.
If you use C89 and can’t use compound literals, you can use (type)0, but that wouldn’t allow for structure or union types.
Just as a note, Gcc has an extension Statements and Declarations in Expressions.
This is very nasty:
#define MY_MACRO_FUNC(ptr, type) (*(type*)ptr); \
(ptr = /* Pointer arithmetic and other stuff here */)
It may have unexpected results in certain inoccuous-looking circumstances, such as
if (foo) bar = MY_MACRO_FUNC(ptr, int);
Consider: what happens then if foo is 0?
I think you would be better off implementing this in a form that assigns the popped value instead of 'returning' it:
#define MY_POP(stack, type, v) do { \
if (!stack) abort_abort_abort(); \
v = *((type *) stack); \
stack = (... compute new value ...); \
} while (0)

Is this function macro safe?

Can you tell me if anything and what can go wrong with this C "function macro"?
#define foo(P,I,X) do { (P)[I] = X; } while(0)
My goal is that foo behaves exactly like the following function foofunc for any POD data type T (i.e. int, float*, struct my_struct { int a,b,c; }):
static inline void foofunc(T* p, size_t i, T x) { p[i] = x; }
For example this is working correctly:
int i = 0;
float p;
foo(&p,i++,42.0f);
It can handle things like &p due to putting P in parentheses, it does increment i exactly once because I appears only once in the macro and it requires a semicolon at the end of the line due to do {} while(0).
Are there other situations of which I am not aware of and in which the macro foo would not behave like the function foofunc?
In C++ one could define foofunc as a template and would not need the macro. But I look for a solution which works in plain C (C99).
The fact that your macro works for arbitrary X arguments hinges on the details of operator precedence. I recommend using parentheses even if they happen not to be necessary here.
#define foo(P,I,X) do { (P)[I] = (X); } while(0)
This is an instruction, not an expression, so it cannot be used everywhere foofunc(P,I,X) could be. Even if foofunc returns void, it can be used in comma expressions; foo can't. But you can easily define foo as an expression, with a cast to void if you don't want to risk using the result.
#define foo(P,I,X) ((void)((P)[I] = (X)))
With a macro instead of a function, all you lose is the error checking. For example, you can write foo(3, ptr, 42) instead of foo(ptr, 3, 42). In an implementation where size_t is smaller than ptrdiff_t, using the function may truncate I, but the macro's behavior is more intuitive. The type of X may be different from the type that P points to: an automatic conversion will take place, so in effect it is the type of P that determines which typed foofunc is equivalent.
In the important respects, the macro is safe. With appropriate parentheses, if you pass syntactically reasonable arguments, you get a well-formed expansion. Since each parameter is used exactly once, all side effects will take place. The order of evaluation between the parameters is undefined either way.
The do { ... } while(0) construct protects your result from any harm, your inputs P and I are protected by () and [], respectively. What is not protected, is X. So the question is, whether protection is needed for X.
Looking at the operator precedence table (http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence), we see that only two operators are listed as having lower precedence than = so that the assignment could steal their argument: the throw operator (this is C++ only) and the , operator.
Now, apart from being C++ only, the throw operator is uncritical because it does not have a left hand argument that could be stolen.
The , operator, on the other hand, would be a problem if X could contain it as a top level operator. But if you parse the statement
foo(array, index, x += y, y)
you see that the , operator would be interpreted to delimit a fourth argument, and
foo(array, index, (x += y, y))
already comes with the parentheses it requires.
To make a long story short:
Yes, your definition is safe.
However, your definition relies on the impossibility to pass stuff, more_stuff as one macro parameter without adding parentheses. I would prefer not to rely on such intricacies, and just write the obviously safe
#define foo(P, I, X) do { (P)[I] = (X); } while(0)

How to check if a parameter is an integral constant expression in a C preprocessor macro?

I'm currently cleaning up an existing C-library to publish it shamelessly.
A preprocessor macro NPOT is used to calculate the next greater power of two for a given integral constant expression at compile time. The macro is normally used in direct initialisations. For all other cases (e.g. using variable parameters), there is an inline function with the same function.
But if the user passes a variable, the algorithm expands to a huge piece of machine code. My question is:
What may I do to prevent a user from passing anything but an integral constant expression to my macro?
#define NPOT(x) complex_algorithm(x)
const int c=10;
int main(void) {
int i=5;
foo = NPOT(5); // works, and does everything it should
foo = NPOT(c); // works also, but blows up the code extremely
foo = NPOT(i); // blows up the code also
}
What I already tried:
Define the macro to #define NPOT(x) complex_algorithm(x ## u). It still works and throws a - even if hardly helpful - compiler error for variable parameters. Unless there is no variable like iu... Dirty, dangerous, don't want it.
Documentation, didn't work for most users.
You can use any expression that needs a constant integral expression and that will then be optimized out.
#define NPOT(X) \
(1 \
? complex_algorithm(X) \
: sizeof(struct { int needs_constant[1 ? 1 : (X)]; }) \
)
eventually you should cast the result of the sizeof to the appropriate integer type, so the return expression is of a type that you'd expect.
I am using an untagged struct here to
have a type so really no temporary is produced
have a unique type such that the expression can be repeated anywhere in the code without causing conflicts
trigger the use of a VLA, which is not allowed inside a struct as of C99:
A member of a structure or union may have any object type other than a
variably modified type.
I am using the ternary ?: with 1 as the selecting expression to ensure that the : is always evaluated for its type, but never evaluated as an expression.
Edit: It seems that gcc accepts VLA inside struct as an extension and doesn't even warn about it, even when I explicitly say -std=c99. This is really a bad idea of them.
For such a weird compiler :) you could use sizeof((int[X]){ 0 }), instead. This is "as forbidden" as the above version, but additionally even gcc complains about it.
#define INTEGRAL_CONST_EXPR(x) ((void) sizeof (struct {int a:(x);}), (x))
This will give a compile error if x is not a integral constant expression.
my_function(INTEGRAL_CONST_EXPR(1 + 2 + 3)); // OK
my_function(INTEGRAL_CONST_EXPR(1.0 + 2 + 3)); // compile error
Note that this solution does not work for initializing a static variable:
static int a = INTEGRAL_CONST_EXPR(2 + 3);
will trigger a compile error because of an expression with , is not a constant expression.
As #JensGustedt put in the comment, an integral constant expression resolving to a negative integer number cannot be used in this solution as bit-field width cannot be negative.

Resources