I'm looking for a creative solution for making sure that variables delivered to a specific macro are declared with type volatile in C language, with TMS470 compiler. meaning:
good method:
volatile int *_p_reg;
VOLATILE_MACRO(_p_reg);
compilation failure:
int *_p_reg;
VOLATILE_MACRO(_p_reg);
I wish to perform the verification after the compilation, meaning going over the disassembly or the debug information and identify those calls.
I can't seem to find any evidence for the volatile in the debug info.
any ideas?
thanks!
I wouldn't expect there to be any, but of course it's totally up to the compiler.
You could of course re-architect it so that the macro does the whole definition, i.e.
#define VOLATILE_MACRO(t, p) volatile t p
and use it like:
VOLATILE_MACRO(int, _p_reg);
but of course that might not work for you.
Two possible solutions using gcc extensions. The run-time version uses __builtin_types_compatible_p and an assert. The compile-time version is similar but uses a hack to get a static assert which fires at compile-time (albeit with a rather cryptic error message):
Run-time
#include <stdio.h>
#include <assert.h>
#define VOLATILE_MACRO(p) \
assert (__builtin_types_compatible_p(typeof(p), typeof(volatile int *)))
int main()
{
volatile int * x;
int * y;
VOLATILE_MACRO(x); // <<< OK
VOLATILE_MACRO(y); // <<< run-time error
return 0;
}
Compile-time
#include <stdio.h>
#include <assert.h>
#define A BUILD_NAME(__LINE__)
#define BUILD_NAME(line) BUILD_NAME2(line)
#define BUILD_NAME2(line) assert_ ## line
#define STATIC_ASSERT(test) typedef char A[(test) ? 1 : -1]
#define VOLATILE_MACRO(p) \
STATIC_ASSERT (__builtin_types_compatible_p(typeof(p), typeof(volatile int *)))
int main()
{
volatile int * x;
int * y;
VOLATILE_MACRO(x); // <<< OK
VOLATILE_MACRO(y); // <<< compile error
return 0;
}
Note that if you need to support other volatile types then the macro can simply be extended with multiple chained __builtin_types_compatible_p tests, e.g.
#define VOLATILE_MACRO(p) \
assert (__builtin_types_compatible_p(typeof(p), typeof(volatile int *)) ||
__builtin_types_compatible_p(typeof(p), typeof(volatile short *)))
Related
I am trying to use Googletest to execute unit tests on a C macro that uses the _Generic macro. The purpose of using the _Generic macro exists in this case to ensure that the user is passing a typedef struct that can only be one of several different typedefs as a form of run time type checking on the macro. A simple snippet is shown below.
// This is written in the vector.h file
#include <stdbool.h>
#include <stdio.h>
#define IS_TYPE_VALID(T) _Generic( (T), SVector: true, \
IVector: true, \
default: false)
#define INIT_VECTOR(vec, length) do {
bool dat_type = IS_TYPE_VALID(vec);
} while (0)
typedef struct
{
short *array;
size_t allocated_length;
size_t active_length;
} SVector;
typedef struct
{
int *array;
size_t allocated_length;
size_t active_length;
} IVector;
The Googletest test case looks like the example below.
#include <gtest/gtest.h>
extern "C" {
#include "vector.h"
}
TEST (test_short_int, test_push_vector) {
SVector vec;
size_t length = 5;
INIT_VECTOR(vec, length);
}
When I try to compile the simple code I get the following error.
error: expected primary-expression before ':' token #define IS_TYPE_VALID(T) _Generic( (T), SVector: true, \
This error implies that Googletest does not recognize the _Generic macro as legitimate code. This may be an issue of trying to test C code with a C++ framework, but before I retool the unit tests to a C framework like CMocka, I would like to see if there is a way to fix this with Googletest. Any help would be appreciated.
I wanted to know if it was contraindicated to define functions parameters using a macro, knowing they could be variable. Does it break a coding convention ?
example:
#ifdef PREVIOUSLY_DEFINED_MACRO
# define PARAMETERS int a, long b
#else
# define PARAMETERS int a
#endif
void my_func(PARAMETERS)
{
...
}
Thanks !
The code is completely valid but, it's not a good coding practice.
Let's assume the following code snippet:
#ifdef PREV_DEFINED
#define ARGS int x, int y
#else
#define ARGS int x
#endif
#include <stdio.h>
// #define PREV_DEFINED
int func(ARGS) {
// In this context, only 'x' is available
// set by the macro
return (x + y); // ERROR, 'y' is undefined
// You need to make a different code, specifically for
// #ifdef PREV_DEFINED and #else
}
To solve this, you need to make two or more different functions within those #ifdef and #endif flags whose usage is controlled by the PREV_DEFINED macro that depends on how many parameters could be variadic. Eventually, this will make the code look worse.
I have #define function with argument such as DEF_GLOBAL_STRUCT(index) and I need to call this macro from 1 to 100. What is the best way? Can I use for loop?
I made the simple code to show my problem.
#include <stdio.h>
#include <stdint.h>
#define DEF_GLOBAL_STRUCT(index) uint8_t m_##index##_size=2; \
uint32_t m_##index##_data1=0; \
uint32_t m_##index##_data2=0;
DEF_GLOBAL_STRUCT(1)
DEF_GLOBAL_STRUCT(2)
DEF_GLOBAL_STRUCT(3)
// ...
DEF_GLOBAL_STRUCT(100)
int main()
{
printf("%u\n", m_1_size);
return 0;
}
Instead of 100 lines of define function call, can I use something like for loop. Or is there any other solution?
If I have all the control of the code I can define structure and declare it with array. But I can't do it. I need to use this type of define function. That is my limitation.
Your question is asking if you can mix C language with Preprocessor directives to automate the generation of code using both C language and Preprocessor directives.
The answer is not in the way you are trying to do it because of how the Preprocessor and the C compiler work.
The Preprocessor is a separate step from compilation. The idea is that the Preprocessor does a text replacement step of the C source code file to generate a new, temporary version of the C source code file which is then compiled by the C compiler.
It is two different steps and first the Preprocessor does its work and then the C compiler does its work.
What I would suggest is to write a simple program that generates an include file that contains the list of definitions you want to use. Then in the place where you want to put those definitions, use the #include directive to include it at that point.
So if you have a simple script or perhaps a C program something like:
#include <stdio.h>
int main ()
{
int i;
for (i = 1; i <= 100; i++) printf ("DEF_GLOBAL_STRUCT(%d)\n", i);
return 0;
}
Then you compile it and run it from a command line redirecting the output as in:
mygen >junk.h
then in the place you need these directives:
#include <stdio.h>
#include <stdint.h>
#define DEF_GLOBAL_STRUCT(index) uint8_t m_##index##_size=2; \
uint32_t m_##index##_data1=0; \
uint32_t m_##index##_data2=0;
#include "junk.h"
int main()
{
printf("%u\n", m_1_size);
return 0;
}
You can save some typing by defining another macro:
#include <stdio.h>
#include <stdint.h>
#define DEF_GLOBAL_STRUCT(index) uint8_t m_##index##_size=2; \
uint32_t m_##index##_data1=0; \
uint32_t m_##index##_data2=0;
#define DEF_GLOBAL_STRUCT_DECADE(tens) \
DEF_GLOBAL_STRUCT(tens##0) \
DEF_GLOBAL_STRUCT(tens##1) \
DEF_GLOBAL_STRUCT(tens##2) \
DEF_GLOBAL_STRUCT(tens##3) \
DEF_GLOBAL_STRUCT(tens##4) \
DEF_GLOBAL_STRUCT(tens##5) \
DEF_GLOBAL_STRUCT(tens##6) \
DEF_GLOBAL_STRUCT(tens##7) \
DEF_GLOBAL_STRUCT(tens##8) \
DEF_GLOBAL_STRUCT(tens##9)
DEF_GLOBAL_STRUCT(1)
DEF_GLOBAL_STRUCT(2)
DEF_GLOBAL_STRUCT(4)
DEF_GLOBAL_STRUCT(5)
DEF_GLOBAL_STRUCT(6)
DEF_GLOBAL_STRUCT(7)
DEF_GLOBAL_STRUCT(8)
DEF_GLOBAL_STRUCT(9)
DEF_GLOBAL_STRUCT_DECADE(1)
DEF_GLOBAL_STRUCT_DECADE(2)
DEF_GLOBAL_STRUCT_DECADE(3)
DEF_GLOBAL_STRUCT_DECADE(4)
DEF_GLOBAL_STRUCT_DECADE(5)
DEF_GLOBAL_STRUCT_DECADE(6)
DEF_GLOBAL_STRUCT_DECADE(7)
DEF_GLOBAL_STRUCT_DECADE(8)
DEF_GLOBAL_STRUCT_DECADE(9)
DEF_GLOBAL_STRUCT(100)
int main()
{
printf("%u\n", m_1_size);
return 0;
}
Ultimately, I want a compile-time-const macro that in itself includes an assertion.
With a real _Static_assert, I can do something like
#define CEXPR_MACRO_WITH_ASSERTION(Assertion) sizeof(struct{char c; _Static_assert(Assertion,""); })?0:42
(meant for stuff like "compile-time-assert" that the macro value computation won't overflow on any target, and I'd like to keep the assertion in the macro so that it's tightly coupled with the value) but compilers like tcc don't have static asserts so I'd need to emulate it.
#define STATIC_ASSERT(Cexpr,Msg) extern STATIC_ASSERT[(Cexpr)?1:-1]
is a common way to do it but with that extern I can't use it in a struct so I could split it in two
#define STATIC_ASSERT(Cexpr,Msg) extern STATIC_ASSERT_(Cexpr,Msg)
#define STATIC_ASSERT_(Cexpr,Msg) char STATIC_ASSERT[sizeof(char [((Cexpr))?1:-1])] /*ignore Msg for simplicity's sake*/
and use the underscore version in the CEXPR_MACRO_WITH_ASSERTION, but in function context, this will give false positives on compilers that support structs with VLAs in them:
#define STATIC_ASSERT(Cexpr,Msg) extern STATIC_ASSERT_(Cexpr,Msg)
#define STATIC_ASSERT_(Cexpr,Msg) char STATIC_ASSERT[sizeof(char [((Cexpr))?1:-1])]
#define CEXPR_MACRO_WITH_ASSERTION(Assert) (sizeof(struct{char c; STATIC_ASSERT_(Assert,""); })?0:42)
int main(void)
{
int x = 0;
CEXPR_MACRO_WITH_ASSERTION(x);
} //compiles on tcc and gcc (clang rejects it because of the vla in a struct)
so I effectively need:
#define STATIC_ASSERT_(Cexpr,Msg) char STATIC_ASSERT[sizeof(char [((Cexpr)&&ENFORCE_ICEXPR(Cexpr))?1:-1])]
Now I realize on tcc in particular, ENFORCE_ICEXPR (enforce integer constant expression) could be simply replaced with __builtin_constant_p but I was curious if I could do it without the platform dependency.
So I thought I could test Cexpr by trying to assign it to an enum constant and I came up with:
#define ENFORCE_Z(X) _Generic(0LL+(X),ullong:(X),llong:(X)) /*could be just `+(X)` cuz I don't care about floats*/
#define ENFORCE_ICEXPR(X) sizeof( void (*)(enum { ENFORCE_ICEXPR = (int)ENFORCE_Z(X) } ) )
but this gets gcc and clang complaining (unsilencably in gcc's case) about the enum not being visible outside of the declaration (which, incidentally, was the intention here) so I resorted to
#define ENFORCE_ICEXPR(X) sizeof(enum { BX_cat(ENFORCE_ICEXPR__,__COUNTER__) = (int)ENFORCE_Z(X) })
relying on the nonstandard magic macro, __COUNTER__.
My question is, is there a better way to write ENFORCE_ICEXPR(X)?
Perl uses a bit-field instead of an array to define a static_assert fallback:
#define STATIC_ASSERT_2(COND, SUFFIX) \
typedef struct { \
unsigned int _static_assertion_failed_##SUFFIX : (COND) ? 1 : -1; \
} _static_assertion_failed_##SUFFIX PERL_UNUSED_DECL
#define STATIC_ASSERT_1(COND, SUFFIX) STATIC_ASSERT_2(COND, SUFFIX)
#define STATIC_ASSERT_DECL(COND) STATIC_ASSERT_1(COND, __LINE__)
No compiler implements variable length bit-fields.
We have a function macro #define FOO(arg) foo(arg) with int foo(const char* bar);. When NDEBUG is defined FOO is defined as #define FOO(arg) 0, however this causes many compiler warnings because in many cases FOO's return value is not used. The solution should work with with ANSI C compilers and cause no warnings. I've tried:
(void)0: can't be assigend to variable
static int foo(const char* bar) { return 0; } : causes unused static function warning in some modules
static inline int foo(const char* bar) { return 0; } : only works with C99 compilers
Thanks for your help!
edit1:
It's somewhat like a trace macro and used all over the project. Mostly it's just used as a statement like FOO("function x called");, but in a few cases I saw if (FOO("condition a")) { /* some more debug output */ }. With NDEBUG defined and optimization enabled nothing should be left of FOO. I didn't come up with this, but I have to clean up this mess :).
edit2: I should add that for gcc release builds these flags are used: -O3 -Wall -ansi
edit3: For now I'm going with __inline int dummy() { return 0; }. __inline works with both VisualC and GCC in ansi mode.
I guess it's a little bit compiler dependent but this should work:
#ifndef NDEBUG
#define FOO(arg) foo(arg)
#else
#define FOO(arg) ((int)0)
#endif
It prevents the "expression has no effect" warning, it does nothing and its value when used is still 0.
EDITED
It seems it's something not so portable so (now) you have these conditions:
(0) or ((int)0) work at least on VC 2010.
__noop should work on any version of VC after 2003.
VC6 is not a problem because it doesn't emit the C4555 warning at all. For other compilers you may use:
((void)0, 0) It may work on a lot of compilers (maybe it's the more portable one?).
inline int foo(const char* bar) { return 0; } works with any other C99 compiler (as you wrote you may need to declare it as static on gcc).
For any other prehistoric C compiler use the solution pointed by #Jobs: abs(0)
What you could do to prevent the warning is the following:
#ifndef NDEBUG
#define FOO(arg) foo(arg)
#else
#define FOO(arg) abs(0)
#endif
I'm not saying this is ideal (you'd have to make sure stdlib.h is included everywhere, for example) but it does prevent the warning.
I'd do something that is dependent on the C version. In the header file:
#if __STDC_VERSION__ > 199900L
inline int foo(const char* bar) { return 0; }
#else
int foo(const char* bar);
#endif
in one compilation unit
#if __STDC_VERSION__ < 199900L
int foo(const char* bar) { return 0; }
#else
int foo(const char* bar);
#endif
or use for the oldish C version something like Job's answer, that is a function that is certain to be optimized out but that doesn't produce the warning.