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.
Related
I'm writing DEBUG_MSG for print debug messages
#define DEBUG_MSG(msg_str) _DEBUG_MSG_GENERIC(msg_str)
The _DEBUG_MSG_GENERIC is because I'd like to:
Show int message when a input parameter is int
Show char* message when a input parameter is char*
and its implement:
#define _DEBUG_MSG_GENERIC(strs) \
_Generic( (strs), \
int: _DEBUG_MSG_INT, \
default: _DEBUG_MSG_STR \
)(strs)
Now I'd like to implement _DEBUG_MSG_INT and _DEBUG_MSG_STR with Macro function and printf :
#define _DEBUG_MSG_INT(val) printf("%d\n", val);
#define _DEBUG_MSG_STR(str) printf("%s\n", str);
But I got error message is:
main.c:14:30: error: ‘_DEBUG_MSG_INT’ undeclared (first use in this function); did you mean ‘DEBUG_MSG’?
14 | int: _DEBUG_MSG_INT, \
| ^~~~~~~~~~~~~~
How do I solve it?
Does _generic only support function(pointer to function) and not support macro function?
Full Code
#include <stdio.h>
#define DEBUG_MSG(msg_str) _DEBUG_MSG_GENERIC(msg_str)
#define _DEBUG_MSG_GENERIC(strs) \
_Generic( (strs), \
int: _DEBUG_MSG_INT, \
default: _DEBUG_MSG_STR \
)(strs)
#define _DEBUG_MSG_INT(val) printf("%d\n", val)
#define _DEBUG_MSG_STR(str) printf("%s\n", str)
int main()
{
DEBUG_MSG("str");
DEBUG_MSG(5);
}
The problem is that both _DEBUG_MSG_INT and _DEBUG_MSG_STR are function-like macros thus they are only expanded if they are followed by ().
Note that macro expansion takes place before actual C compilation thus _Generic is nothing more than a common identifier at preprocessor stage.
I suggest using _Generic not for selection of the function pointer but rather for a formatting specifier to be used in printf(). Try:
#define _DEBUG_MSG_GENERIC(arg) printf( _DEBUG_MSG_FMTSPEC(arg), arg)
#define _DEBUG_MSG_FMTSPEC(arg) \
_Generic( (arg), int: "%d\n", default: "%s\n")
I believe your issue is because the preprocessor only makes one pass of the source code, so the printf's don't get substituted.
A quick solution would be to define _DEBUG_MSG_INT(val) and _DEBUG_MSG_STR(str) as real functions like so:
void _DEBUG_MSG_INT(int val) {
printf("%d\n", val);
}
void _DEBUG_MSG_STR(char * str) {
printf("%s\n", str);
}
The compiler will optimise out the extra function call overhead and will behave as if you called printf directly.
_Generic is not a preprocessor operation and cannot be used to select preprocessor macro functions. The code after a : in its cases must be a C expression (specifically an assignment-expression).
The code you have in those positions is _DEBUG_MSG_INT and _DEBUG_MSG_STR. Those are preprocessor macro names.
Those preprocessor macros are function-like macros. They are macro-replaced only when they are followed by a (. In your code, there is no ( after them, so they are not replaced.
That means the code after reprocessing looks like int : _DEBUG_MSG_INT,. So the compiler attempts to interpret _DEBUG_MSG_INT as an expression. Since _DEBUG_MSG_INT is not a declared identifier, the compiler reports an error that it is undeclared.
In summary, your code _Generic( (strs), int: _DEBUG_MSG_INT, default: _DEBUG_MSG_STR )(strs) attempts to use an after-preprocessing _Generic selection to select a preprocessing-time macro (either _DEBUG_MSG_INT or _DEBUG_MSG_STR) and then to have that macro treated as a function-like macros with the (strs) that appears after the _Generic. That simply cannot work; an after-preprocessing _Generic cannot select preprocessing macro names.
Example of usage:
void closefrom (int lowfd);
int main()
{
// expected warning
closefrom(-1);
return 0;
}
Specifically: I should implement diagnostics (compiler warning) for function calls. Function located in glibc:
void closefrom (int lowfd);
If lowfd is negative compiler should issue a warning.
Here is some information about closefrom:
https://sourceware.org/pipermail/libc-alpha/2021-August/129718.html
Maybe attribute of the function will somehow help in this?
You can do it like this, but don’t:
void foo(int x) {}
#define foo(x) foo(((int [(x)+1]){0}, (x)))
int main(void)
{
foo(-1);
return 0;
}
The macro attempts to create a compound literal consisting of an array with (x)+1 elements. If x is negative, (x)+1 will be negative or zero, and the compiler will complain about an improper size for the array. (This may require using compiler switches to disable a zero-length array extension.) If x is zero or positive, the compound literal will be discarded by the comma operator, and foo will be called with argument x. (When a macro name is used in its own replacement, it is not replaced again, so the function foo will be called.)
Note that overflow in (x)+1 is possible. You could add a check against INT_MAX to deal with that.
This requires that x be some compile-time expression, which is implied in your question about how to check at compile time.
With Clang or GCC, you can combine a standard _Static_assert with a non-standard statement expression:
#define foo(x) ({ _Static_assert((x) >= 0, "Argument to foo must be nonnegative."); foo(x); })
If foo is always void, you can simply use a _Static_assert with the do … while idiom to give it statement form when a semicolon is appended:
#define foo(x) do { _Static_assert((x) >= 0, "Argument to foo must be nonnegative."); foo(x); } while (0)
If x can be something other than an int, such as a floating-point type, you might want to work on the conditions a bit to deal with issues that arise in the tests and conversions.
want to issue warning only if compiler is able to calculate the value (by optimizations, or if the value is constant). Otherwise just use function without warnin
In short, with GNU extensions:
void foo (int lowfd);
#if defined(__GNUC__) && defined(__OPTIMIZE__)
#define curb(expr, msg) \
__extension__({ \
if (__builtin_constant_p(expr)) { \
if (!(expr)) { \
__attribute__((__noinline__, \
__warning__(msg))) void warnit() {__asm__("");}; warnit(); \
} \
} \
})
#else
#define curb(expr, msg) (void)0
#endif
#define foo(x) (curb(x >= 0, "x is lower than 0"), foo(x))
int main()
{
// expected warning
foo(-1);
return 0;
}
I have this https://gitlab.com/Kamcuk/kamillibc/-/blob/master/libs/curb/src/curb.h#L46 in my tree about the idea of issuing a warning or error if the expression is known at compile time, and if it isn't, failing at runtime or not. The && defined(__OPTIMIZE__) seems not to be needed in this case.
Currently looking at some C code that doesn't make any sense to me. What is (elementSize)? How am supposed to pass arguments to this static function? What is the name of this syntax style so I can learn more abour it?
static int torch_Tensor_(elementSize)(lua_State *L)
{
luaT_pushinteger(L, THStorage_(elementSize)());
return 1;
}
https://github.com/torch/torch7/blob/master/generic/Tensor.c
This is the file I am trying to understand for reference.
Normally
static int torch_Tensor_(elementSize)(lua_State *L)
would mean torch_Tensor_ is a function that takes a single parameter called elementSize that has no type (?! - syntax error) and returns a function that takes a pointer to lua_State and returns an int. This is blatantly invalid (functions cannot return other functions).
But what's actually going on here is that torch_Tensor_ is defined as a function-like macro, so before the compiler even sees this declaration, torch_Tensor_(elementSize) is replaced by something else.
In https://github.com/torch/torch7/blob/master/Tensor.c there is
#include "general.h"
#define torch_Storage_(NAME) TH_CONCAT_4(torch_,Real,Storage_,NAME)
#define torch_Storage TH_CONCAT_STRING_3(torch.,Real,Storage)
#define torch_Tensor_(NAME) TH_CONCAT_4(torch_,Real,Tensor_,NAME)
#define torch_Tensor TH_CONCAT_STRING_3(torch.,Real,Tensor)
#include "generic/Tensor.c"
#include "THGenerateAllTypes.h"
#include "generic/Tensor.c"
#include "THGenerateHalfType.h"
with TH_CONCAT_... defined in lib/TH/THGeneral.h.in:
#define TH_CONCAT_STRING_3(x,y,z) TH_CONCAT_STRING_3_EXPAND(x,y,z)
#define TH_CONCAT_STRING_3_EXPAND(x,y,z) #x #y #z
#define TH_CONCAT_4_EXPAND(x,y,z,w) x ## y ## z ## w
#define TH_CONCAT_4(x,y,z,w) TH_CONCAT_4_EXPAND(x,y,z,w)
So torch_Tensor_ is defined as a macro before generic/Tensor.c is included.
torch_Tensor_(elementSize)
expands to
TH_CONCAT_4(torch_,Real,Tensor_,elementSize)
which expands to
TH_CONCAT_4_EXPAND(torch_,...,Tensor_,elementSize)
... is a placeholder, not real code. Real is defined as a macro in the various THGenerate*Type.h files, so this line actually becomes
TH_CONCAT_4_EXPAND(torch_,char,Tensor_,elementSize)
TH_CONCAT_4_EXPAND(torch_,int,Tensor_,elementSize)
TH_CONCAT_4_EXPAND(torch_,float,Tensor_,elementSize)
...
depending on context. Anyway, the end result is a single identifier of the form
torch_charTensor_elementSize
torch_intTensor_elementSize
torch_floatTensor_elementSize
...
(one token).
The resulting function definition thus looks like e.g.
static int torch_charTensor_elementSize(lua_State *L)
{
...
}
depending on which context generic/Tensor.c was included in.
The reason things are done this way is to have what amounts to the same code, but for multiple different types. In C++ you would write a function template:
namespace torch {
template<typename Real>
static int Tensor_elementSize(lua_State *L) { ... }
}
But C has no templates (nor namespaces), so the only way to get "generic" code like this is to do it manually with macros and preprocessing tricks (and manually "decorating" names; e.g. the elementSize function for floats is really called torch_floatTensor_elementSize).
All we're really trying to do is abstract over a type parameter, here called Real.
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.)
I was writing some test code in C. By mistake I had inserted a ; after a #define, which gave me errors. Why is a semicolon not required for #defines?
More specifically :
Method 1: works
const int MAX_STRING = 256;
int main(void) {
char buffer[MAX_STRING];
}
Method 2: Does not work - compilation error.
#define MAX_STRING 256;
int main(void) {
char buffer[MAX_STRING];
}
What is the reason of the different behavior of those codes? Are those both MAX_STRINGs not constants?
#define MAX_STRING 256;
means:
whenever you find MAX_STRING when preprocessing, replace it with 256;. In your case it'll make method 2:
#include <stdio.h>
#include <stdlib.h>
#define MAX_STRING 256;
int main(void) {
char buffer [256;];
}
which isn't valid syntax. Replace
#define MAX_STRING 256;
with
#define MAX_STRING 256
The difference between your two codes is that in first method you declare a constant equal to 256 but in the second code you define MAX_STRING to stand for 256; in your source file.
The #define directive is used to define values or macros that are used by the preprocessor to manipulate the program source code before it is compiled. Because preprocessor definitions are substituted before the compiler acts on the source code, any errors that are introduced by #define are difficult to trace.
The syntax is:
#define CONST_NAME VALUE
if there is a ; at the end, it's considered as a part of VALUE.
to understand how exactly #defines work, try defining:
#define FOREVER for(;;)
...
FOREVER {
/perform something forever.
}
Interesting remark by John Hascall:
Most compilers will give you a way to see the output after the preprocessor phase, this can aid with debugging issues like this.
In gcc it can be done with flag -E.
#define is a preprocessor directive, not a statement or declaration as defined by the C grammar (both of those are required to end with a semicolon). The rules for the syntax of each one are different.
define is a preprocessor directive, and is a simple replacement, it is not a declaration.
BTW, as a replacement it may contain some ; as part of it:
// Ugly as hell, but valid
#define END_STATEMENT ;
int a = 1 END_STATEMENT // preprocessed to -> int a = 1;
Both constants? No.
The first method does not produce a constant in C language. Const-qualified variables do not qualify as constants in C. Your first method works only because past-C99 C compilers support variable-length arrays (VLA). Your buffer is a VLA in the first case specifically because MAX_STRING is not a constant. Try declaring the same array in file scope and you'll get an error, since VLAs are not allowed in file scope.
The second method can be used to assign names to constant values in C, but you have to do it properly. The ; in macro definition should not be there. Macros work through textual substitution and you don't want to substitute that extra ; into your array declaration. The proper way to define that macro would be
#define MAX_STRING 256
In C language, when it comes to defining proper named constants, you are basically limited to macros and enums. Don't try to use const "constants", unless you really know that it will work for your purposes.
Because that is how the syntax was decided for the precompiler directives.
Only statements end with a ; in c/c++, #define is a pre-processor directive and not a statement.
The second version does not define a constant as far as the language is concerned, just a substitution rule for a block of text. Once the preprocessor has done it's job, the compiler sees
char buffer [256;];
which is not syntactically valid.
The moral of the story: prefer the const int MAX_STRING = 256; way as that helps you, the compiler, and the debugger.
This preprocessor directive:
#define MAX_STRING 256;
tells the preprocessor to replace all MAX_STRINGs with 256; - and with the semicolon. Preprocessor statements don't need a semicolon at the end. If you put one, the preprocessor actually thinks you mean it with a semicolon.
If you are confused with #defines for constants, const int would probably be easier to comprehend.
If you want to learn more on how to properly use these preprocessor directives, try looking at this website.