Defining constant-variables with a C macro - c

I am trying to define a 'variable' with a macro which can later be used as a constant value ...I have now run out of ideas and wondering if anyone can tell me if I've missed anything:
This is what I originally coded, but C does not recognise 'name' as a constant
qv. compile error C2099: initializer is not a constant
#define DECL(name,value) static const unsigned long int name = value
DECL(FOO, 0xFFFFFFFF)
My next attempt was to write a macro that would #define the value for me ...But the compiler complains about the embedded # : "error: '#' is not followed by a macro parameter"
qv. Escaping a # symbol in a #define macro?
#define DECL(name,value) #define name (value)UL
DECL(FOO, 0xFFFFFFFF)
At ^-this-^ link, ybungalobill claims v-this-v works ... but it doesn't
#define DECL(hash, name, value) hash define name (value)UL
DECL(#, FOO, 0xFFFFFFFF)
I managed to get my code to compile with this enum trick (inspired by the first link) ...it works on my computer, but as this issue is ultimately about creating portable code [portable between languages as well as platforms!] I am worried about the sizeof and signed'ness of the value. qv. What is the size of an enum in C?
#define DECL(name,value) enum { name = value } ;
DECL(FOO, 0xFFFFFFFF)
Here are some lines of code which may use the above FOO value:
int array[FOO];
static const unsigned long int BAR = FOO + 1 ;
int main (void) {
unsigned long int var1 = FOO;
printf("%d - %d\n", FOO, sizeof(FOO));
}

A macro definition cannot include preprocessor directives, so you can't #define something that expands to another #define.
The const keyword in C doesn't mean "constant"; it means "read-only". A "constant" expression is one that can be evaluated at compile time. A const object is one whose value may not be modified. For example:
const int r = rand();
r is const, meaning you can't modify it after it's been initialized, but it's not "constant" (it can't be, since the value returned by rand() can't be determined until run time).
Using a constant expression as the initializer doesn't change this. (It does in C++.)
The usual way to define a named constant in C is to define it directly as a macro. For example, rather than
#define DECL(name,value) #define name (value)UL
DECL(FOO, 0xFFFFFFFF)
just write:
#define FOO 0xFFFFFFFFUL
For the special case of constants of type int, you can use an enum declaration:
enum { max = 1000 };
This defines an anonymous enumeration type and a constant max of that type. max is a constant of type int. It's defined that way for historical reasons; it would probably make more sense if max were of the enumeration type (as it is in C), but it isn't.

Your issue is not related to macros in any way.
I am trying to define a 'variable' [...] which can later be used as a constant value
You cannot do this in the sense that this variable can be use as an initialiser.
It would stay a variable.
For further reading: Error "initializer element is not constant" when trying to initialize variable with const

Related

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__;

What is the right declaration of constants in C?

I am actualy using something like this to make constansts for my error function. Is this fine or should I do this somehow else?
// declares 1 and 0 as a FALSE and TRUE
#define TRUE 1
#define FALSE !TRUE
// declares "error types"
const enum {
SYNTAX = 0,
ZERO_OPERATOR = 1,
ZERO_MINUS = 2
};
How I am using "error types" constants in code:
If (!something) error(SYNTAX); // there is a switch in error function which prints the error
There are several different ways to define symbolic constants in C:
Using the preprocessor: #define FOO something
Using enumeration constants: enum { FOO=1, BAR=10, BLETCH=100 };
Using const-qualified variables: const double PI=3.14159265359;
Each has its pros and cons.
Preprocessor macros are basically just text replacements, and can be used for simple values:
#define FOO 10
#define STR "This is a test"
#define PI 3.14159265359
or for more complex expressions
#define BAR (FOO * PI + BLETCH)
The problem is that preprocessor macros are replaced during the preprocessing stage, so after your code is compiled the symbols FOO, STR, PI, and BAR no longer exist (which can make assembly-level debugging difficult), and they don't obey scoping rules (i.e., if you create the macro within a function, it's visibility won't be limited to just that function, it will be visible to any code following the function definition).
You can use enumeration constants for integer values:
enum { FOO = 1, BAR = 10, BLETCH = 100 };
These are not replaced after preprocessing, so they're visible in debuggers. Values are known at compile time, so they can be used for array sizes or cases in switch statements. Enumeration constants occupy the same name space as variable and function names, so you can't use the same symbol for an enumeration constant and a variable. Enumeration constants do obey scoping rules; if you define the enum type within a function, those enumeration constants will not be visible outside of the function body.
You cannot use enumeration constants for non-int values (strings, floats, any integer value wider than int).
You can use const-qualified variables:
const double PI = 3.14159265359;
const char * const STR = "This is a string constant";
const int FOO = 10;
Almost as flexible as preprocessor macros, symbols aren't replaced by the preprocessor. Like enumeration constants, variables obey scoping rules. Downside is that storage must be allocated for all these objects at runtime, and they don't count as compile-time constants, meaning they can't be used for things like cases in a switch statement.
No one scheme is always "best"; it really depends on what you need.
For my part, I use the enum method for related integer constants (error codes, machine states, etc.), and const-qualified variables for just about everything else. I rarely use preprocessor macros for symbolic constants.

How to use const int in _Static_assert?

Preamble: I want to statically check amount of struct members in C program, so I created two macros, each of them creates constant int storing __LINE__ into variable:
#include <stdio.h>
#include <string.h>
#define BEGIN(log) const int __##log##_begin = __LINE__;
#define END(log) const int __##log##_end = __LINE__;
BEGIN(TEST);
struct TEST {
int t1;
int t2;
float t3;
int t4;
int t5;
int t6;
};
END(TEST)
main()
{
static_assert(__TEST_end - __TEST_begin == 6 + 3, "not_equal");
}
When I use C++ compiler with -std=c++11 option (c++ test.cpp -std=c++11), it works fine, but the same code (with replacement of static_assert to _Static_assert) doesn't work in C(gcc version 4.8.4) with a strange error as this expression could be evaluated at a compile time:
test.c: In function ‘main’: test.c:18:17: error: expression in static
assertion is not constant _Static_assert(__TEST_end - __TEST_begin
== 6 + 4, "not_equal");
How can I fix this error or achieve the original goal in C?
In C a variable even if defined with const is not a constant expression. _Static_assert requires its first parameter to be a constant expression. Therefore the same thing that can be done in C++ cannot be done in C.
You can do a runtime check instead; use assert.
Note that this method won't guard you against a programmer typing out two members in the same line or using multiple single line declarations of the same type, or adding an empty line (or a comment). Instead of forcing a programmer to follow a string coding pattern, just so that this assert will catch the error, it is less error prone to simply require the programmer to define a correct number of members. It is strictly better, because you can make the an undetectable error either way, but at least doesn't have to worry about the strict coding pattern.
A solution for your issue would be to use an anonymous enumeration. Instead of:
#define BEGIN(log) const int __##log##_begin = __LINE__
#define END(log) const int __##log##_end = __LINE__
Do:
#define BEGIN(log) enum { __##log##_begin = __LINE__ }
#define END(log) enum { __##log##_end = __LINE__ }
This is allowed in C11 since, unlike a const int (or even static const int) variable, an enumeration constant is defined to be an integral constant expression.
(As an aside, I omitted the terminal semicolon from my version of your BEGIN()/END() macros. In my opinion, declaration macros should not include a terminal semicolon, that should be provided by the macro user, so the macro behaves more like a non-macro C declaration.)

Symbolic constants in C (#define statement)

After reading through some of K&R's The C Programming Language I came across the #define symbolic constants. I decided to define...
#define INTEGER_EXAMPLE 2
#define CHAR_EXAMPLE 2
...so my question is how does C know if I'm defining an int or a char type?
#define-d names have no types. They just define textual replacements.
What the compiler is seeing is the preprocessed form. If using GCC, try gcc -C -E somesource.c and have a look at the (preprocessed) output.
In the 1980s the preprocessor was a separate program.
Read about the cpp preprocessor, and preprocessor and C preprocessor wikipages.
You could even define ill-defined names like
#define BAD #*?$ some crap $?
And even more scary you can define things which are syntactically incomplete like
#define BADTASTE 2 +
and later code BADTASTE 3
Actually, you want to use parenthesis when defining macros. If you have
#define BADPROD(x,y) x*y
then BADPROD(2+3,4+5) is expanded to 2+3*4+5 which the compiler understands like 2+ (3*4) +5; you really want
#define BETTERPROD(x,y) ((x)*(y))
So that BETTERPROD(2+3,4+5) is expanded to ((2+3)*(4+5))
Avoid side-effects in macro arguments, e.g. BETTERPROD(j++,j--)
In general, use macros with care and have them stay simple.
Regarding these defines, it doesn't, the expanded macros doesn't have a type. The pre-processor which processes the #define is just replacing text within the source code
When you use these defines somewhere, e.g.
int i = INTEGER_EXAMPLE;
This will expand to
int i = 2;
Here the literal 2 (which in this context is an int) is assigned to an int.
You could also do:
char c = INTEGER_EXAMPLE;
Here too, the literal 2 is an int, and it is assigned to a char. 2 is within the limits of a char though, so all is ok.
You could even do:
int INTEGER_EXAMPLE = 2;
This would expand to
int 2 = 2;
Which isn't valid C.
#define STRING VALUE
is just an instruction for the pre-processor to replace the STRING with VALUE
afterwards the compiler will take control and will check the types
It doesn't, this is the preprocessor. The type of the constant is dependent on the context in which it is used. For instance:
#define INT_EXAMPLE 257
char foo = INT_EXAMPLE;
will attempt to assign 257 in a char context which should generate a warning unless char has more than 8 bits on your computer.
#Defines are nothing but literal replacements of values. You might want to use
static const
As it respects scope and is type-safe. Try this:
#define main no_main
int main() // gets replaced as no_main by preprocessor
{
return 0;
}
Should give you linking errors. Or you could try and fool your teacher by this
#define I_Have_No_Main_Function main //--> Put this in header file 1.h
#include"1.h"
int I_Have_No_Main_Function()
{
return 0;
}
It doesn't. The #define statements are processed before the compiler starts its work. Basically the pre-processor does a search and replace for what you wrote and replaces it, for instance, all instances of INTEGER_EXAMPLE are replaced with the string 2.
It is up to the compiler to decide the type of that 2 based on where it's used:
int x = INTEGER_EXAMPLE; // 2 is an integer
char y = INTEGER_EXAMPLE; // 2 is a char
Preprocessor cannot know the type of the macro definition. Preprocessor will just replace all occurrence of 'CHAR_EXAMPLE' with '2'. I would use cast:
#define CHAR_EXAMPLE ((char)2)

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