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.)
Related
I am building some generic things in C.
Here is the code:
// main.c
#include <stdio.h>
#define T int;
#include "test.h"
int main()
{
return 0;
}
// test.h
#define _array_is_pointer(T) ( \
{ \
T _value; \
__builtin_classify_type(_value) == 5; \
})
#ifdef T
#if _array_is_pointer(T)
struct array_s
{
T *items;
}
void array_push(struct array_s * array, T value)
{
// push method for pointer.
}
#else
struct array_s
{
T *items;
}
void array_push(struct array_s * array, T value)
{
// push method for non-pointer.
}
#endif
#endif
** edited: add more code in test.h **
I would like the preprocessor runs different code when T is pointer or non-pointer.
But I got an error token "{" is not valid in preprocessor expressions.
Is it possible to do that?
I would like the preprocessor runs different code when T is pointer or non-pointer.
Is it possible to do that?
No, it is not possible. Preprocessor is not aware of types.
If you really want this, pass a mark if T is a pointer or not as a separate macro.
#define T int*
#define T_IS_A_POINTER 1
#include "test.h"
Or have separate calls:
#define T int*
#include "test_a_pointer.h"
#define T int
#include "test_not_a_pointer.h"
The preprocessor doesn't know whether T is a pointer, because preprocessing happens before semantic analysis of the program. All the preprocessor sees are tokens; it knows that 42 is a number and take42, but that's it. The only definitions it knows about are preprocessor #defines.
Moreover, in C, functions --even builtin constant functions like sizeof and __builtin_classify_type-- cannot be evaluated by the preprocessor. The preprocessor cannot evaluate block expressions either, but there wouldn't be much point so it has no idea what a variable is and thus doesn't need declarations. The only identifier you can use in an #if preprocessor conditional are macro definitions which expand to integer constants (or entire expressions containing only arithmetic operations on integer constants).
There is the _Generic construct introduced in C11, which allows you to generate different expressions based on the type of a controlling expression. But it can only be used to generate expressions, not declarations, so it's probably not much help either.
There is no issue while writing multi-line code-snippet in
#define _array_is_pointer(T) ( \
{ \
T _value; \
__builtin_classify_type(_value) == 5; \
})
But, as you have know, the first step done before passing the code to compiler is to create an Expanded source code. In this step, all the five lines woud be pasted whereever you would have written _array_is_pointer(T) and hence resulting code would have :
#if (
{
T _value;
__builtin_classify_type(_value) == 5;
})
and here is a blunder. One can not write multiple lines like this in if clause, nor you could do this using {}. And hence, you got the error token "{" is not valid in preprocessor expressions.
Hence, you would have to write a single expression to in if clause preprocessor.
How might we write a preprocessor macro to replace every instance of:
func(
with
func((DemoUnion)?
Also, maybe a macro to replace func((DemoUnion)(DemoUnion) with func((DemoUnion)?
By the way, below is an example of how DemoUnion might be defined:
union DemoUnion {
char c;
short s;
int i;
float f;
}; typedef union DemoUnion DemoUnion;
// the typedef allows us to declare instances by writing
// DemoUnion instanceName;
// instead of:
// union DemoUnion instanceName;
Also, C allows us to cast to union types pretty easily:
(so long as the input to the cast is one of the types included in the union)
int main() {
DemoUnion big = 0;
char c = 1;
big = (DemoUnion) c; // cast char to union type
func(big);
func((DemoUnion) c);
}
How might we write a preprocessor macro to replace every instance of:
func(
with
func((DemoUnion)?
We wouldn't write such a macro, because C does not afford a way to do it. Macro expansion replaces the macro identifier and, for function-like macros, its argument list, with the macro's replacement text. The ( character cannot be part of a macro identifier, and it is not, by itself, an argument list. Thus, func( is not a unit that is subject to macro expansion.
You could, however, do this:
#define func(x) func((DemoUnion)(x))
That will have about the effect you describe, but it is specific to argument-list length. Also, you do not have to worry about recursive expansion; C specifies that it does not happen.
Also, maybe a macro to replace func((DemoUnion)(DemoUnion) with
func((DemoUnion)
Nope. Macro replacement replaces macros, not general text patterns. Anyway, anywhere that a (DemoUnion) cast is valid, (DemoUnion)(DemoUnion) is also valid and equivalent.
But note well that you have a serious misconception:
Also, C allows us to cast to union types pretty easily: (so long as
the input to the cast is one of the types included in the union)
On the contrary, C does not allow casting to or from union types. At all. Some compilers will accept such casts as an extension, but it is non-standard. The closest the (C2011) standard permits would involve using a compound literal:
DemoUnion u = (DemoUnion) { .c = c };
Note well that although part of the syntax for a compound literal resembles a cast operator, there is no cast there. But really, why do that, when you can just use an ordinary initializer:
DemoUnion u = { .c = c };
... or ordinary member assignment:
DemoUnion u;
u.c = c;
as the situation warrants.
Going the other way, of course, you should just use member selection:
char c2 = u.c;
It is not possible to have define name with "(". However, you may use function macro:
#define FOO(X) FOO((DemoUnion) (X))
or with variable number of arguments:
#define FOO(...) FOO((DemoUnion) __VA_ARGS__)
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
I am trying to use an open source R tree however I get errors. I have spent several hours to fix it but could not. Please help.
The part of the code is as below:
#include <stdio.h>
#include <math.h>
#ifndef M_PI
# define M_PI 3.1415926535
#endif
#ifndef ABS
# define ABS(a) ((a) > 0 ? (a) : -(a))
#endif
#define EP .0000000001
const double log_pi = log(M_PI);
double sphere_volume(double dimension)
{
double log_gamma, log_volume;
log_gamma = gamma(dimension/2.0 + 1);
log_volume = dimension/2.0 * log_pi - log_gamma;
return exp(log_volume);
}
I get the following errors:
1>c:\users\user\desktop\r\gammavol.c(14): error C2099: initializer is not a constant
1>c:\users\user\desktop\r\gammavol.c(21): warning C4013: 'gamma' undefined; assuming extern returning int
line 14 is const double log_pi = log(M_PI);
line 21 is log_gamma = gamma(dimension/2.0 + 1);
thanks in advance
The two error messages are quite clear.
The first one says that you cannot initialize a variable with a non-constant value.
while log(M_PI) is indeed constant, the compiler cannot treat it as such, because it doesn't know if the function log() always returns the same result. It does, but the compiler must assume it doesn't, hence "non-constant".
The second one says that the function gamma you try to call here is not defined.
Hence, it assumes it is an extern int gamma(). As it is unclear where this function is declared, you should at least include the appropriate header file containing its prototype.
This line is the cause of your first error:
const double log_pi = log(M_PI);
The expression log(M_PI) is not constant and cannot be used in the initialization. Either use the following instead, or move the definition inside your main function and remove the const:
const double log_pi = 1.1447298858494002;
The second error is because the compiler cannot find the function gamma. It seems that it is not defined in your math.h. If you're not getting linker errors, I suggest that you add:
double gamma (double);
The right thing to do would be to find the proper header file to include. This question could shed some light.
A static const needs to be initialized at compile time, you put a function call there. Advanced compilers such as gcc can compute something like this at compile time anyway and will just warn about the illegal construct instead of erroring out. Yours apparently is not capable of this.
The other thing is that gamma() is not a standard libmath function, they are some Unix non-standard thing you would find on BSDs and Linux but not (going by your path names) on your Windows. It is deprecated anyway and there are tgamma() and lgamma() which are standardized in C99.
log(M_PI) is not a constant expression, its a constant qualified object which is not constants in C language terminology. For this you need to declare a named constant you should use either #define or enum, but not const qualifier. Variables of const double type are not constants in C.
#define log_pi log(M_PI)
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)