I came across macro definition like below. Is the definition of the macro RVS_E(_I, _E) valid?
And how does the macro RVS_C() work (as it is dependent on RVS_E) and what would be the output of RVS_C
extern unsigned int rvs_trace_port;
/* Instrumentation point */
void RVS_Ipoint(unsigned int);
/* Instrumentation macros and functions */
#define RVS_I(_I) (rvs_trace_port = (_I))
#define RVS_E(_I,_E) ((void)RVS_I((_I)),(_E))
#define RVS_C(_I,_C) (RVS_E(_I,0)?(_C):(_C))
#define RVS_T(_I) RVS_E((_I),1)
#define RVS_F(_I) RVS_E((_I),0)
unsigned int RVS_CM (unsigned int * k, unsigned int pos, unsigned int b);
unsigned int RVS_DM (unsigned int id, unsigned int * k, unsigned int b);
#define RVS_DML RVS_DM
Following is the example code where these macros are used (it is an autogenerated "instrumented" code and hence looks a bit crazy)
if ( ( rvs_tmp_k_362=0, RVS_DM(362,&rvs_tmp_k_362,(unsigned int)(RVS_CM(&rvs_tmp_k_362,2,(unsigned int)((nvHist_Queue.DataPtr != (uint8*)&nvHist_QData)))
{
.....
}
Related
Why does this .c file #include itself?
https://github.com/powturbo/TurboPFor-Integer-Compression
vsimple.c
#define USIZE 8
#include "vsimple.c"
#undef USIZE
#define USIZE 16
#include "vsimple.c"
#undef USIZE
#define USIZE 32
#include "vsimple.c"
#undef USIZE
#define USIZE 64
#include "vsimple.c"
#undef USIZE
The file includes itself so the same source code can be used to generate 4 different sets of functions for specific values of the macro USIZE.
The #include directives are actually enclosed in an #ifndef, which limits the recursion to a single level:
#ifndef USIZE
// common definitions
...
//
#define VSENC vsenc
#define VSDEC vsdec
#define USIZE 8
#include "vsimple.c"
#undef USIZE
#define USIZE 16
#include "vsimple.c"
#undef USIZE
#define USIZE 32
#include "vsimple.c"
#undef USIZE
#define USIZE 64
#include "vsimple.c"
#undef USIZE
#else // defined(USIZE)
// macro expanded size specific functions using token pasting
...
#define uint_t TEMPLATE3(uint, USIZE, _t)
unsigned char *TEMPLATE2(VSENC, USIZE)(uint_t *__restrict in, size_t n, unsigned char *__restrict out) {
...
}
unsigned char *TEMPLATE2(VSDEC, USIZE)(unsigned char *__restrict ip, size_t n, uint_t *__restrict op) {
...
}
#endif
The functions defined in this module are
// vsencNN: compress array with n unsigned (NN bits in[n]) values to the buffer out. Return value = end of compressed output buffer out
unsigned char *vsenc8( unsigned char *__restrict in, size_t n, unsigned char *__restrict out);
unsigned char *vsenc16(unsigned short *__restrict in, size_t n, unsigned char *__restrict out);
unsigned char *vsenc32(unsigned *__restrict in, size_t n, unsigned char *__restrict out);
unsigned char *vsenc64(uint64_t *__restrict in, size_t n, unsigned char *__restrict out);
// vsdecNN: decompress buffer into an array of n unsigned values. Return value = end of compressed input buffer in
unsigned char *vsdec8( unsigned char *__restrict in, size_t n, unsigned char *__restrict out);
unsigned char *vsdec16(unsigned char *__restrict in, size_t n, unsigned short *__restrict out);
unsigned char *vsdec32(unsigned char *__restrict in, size_t n, unsigned *__restrict out);
unsigned char *vsdec64(unsigned char *__restrict in, size_t n, uint64_t *__restrict out);
They are all expanded from the two function definitions in vsimple.c:
unsigned char *TEMPLATE2(VSENC, USIZE)(uint_t *__restrict in, size_t n, unsigned char *__restrict out) {
...
}
unsigned char *TEMPLATE2(VSDEC, USIZE)(unsigned char *__restrict ip, size_t n, uint_t *__restrict op) {
...
}
The TEMPLATE2 and TEMPLATE3 macros are defined in conf.h as
#define TEMPLATE2_(_x_, _y_) _x_##_y_
#define TEMPLATE2(_x_, _y_) TEMPLATE2_(_x_,_y_)
#define TEMPLATE3_(_x_,_y_,_z_) _x_##_y_##_z_
#define TEMPLATE3(_x_,_y_,_z_) TEMPLATE3_(_x_, _y_, _z_)
These macros are classic preprocessor constructions to create identifiers via token pasting. TEMPLATE2 and TEMPLATE2_ are more commonly called GLUE and XGLUE.
The function template starts as:
unsigned char *TEMPLATE2(VSENC, USIZE)(uint_t *__restrict in, size_t n, unsigned char *__restrict out) ...
It is expanded in the first recursive inclusion with USIZE defined as 8 into:
unsigned char *vsenc8(uint8_t *__restrict in, size_t n, unsigned char *__restrict out) ...
The second recursive inclusion, with USIZE defined as 16, expands the template as:
unsigned char *vsenc16(uint16_t *__restrict in, size_t n, unsigned char *__restrict out) ...
and 2 more inclusions define vsenc32 and vsenc64.
This usage of preprocessed source code is more common with separate files: one for the instantiating part that has all the common definitions, especially the macros, and a separate file for the code and data templates, which is included multiple times with different macro definitions.
A good example is the generation of enums, string and structures arrays from atom and opcode definitions in QuickJS.
The accepted answer by #chqrlie 100% explains what is happening. This is just a complementary commentary.
If using C++ we could define two template functions to provide all the implementations of vsenc8, vsenc16, vsenc32, vsenc64 and vsdec8, vsdec16, vsdec32, vsdec64. In contrast, however, C is a very simple language and does not support templates. A common trick to have the same power (in uglier packaging) is to use the dumb macro facility of the language and let the C preprocessor do the equivalent job for us. Most C programmers of some experience will encounter and use this kind of construct repeatedly during their careers.
What makes this particular example a bit tedious to understand is that the implementation file is unconventionally parsed 5 times to first have some preparatory definitions and then the four variants of the two functions. The first pass (inside #ifndef USIZE preprocessor block) will have the needed macros and non-variant stuff defined and will recursively #include itself four times with different USIZE values (8, 16, 32, 64) as template values. When recursively included, the corresponding #else preprocessor block is parsed with the result of two functions generated according to the value of USIZE macro constant used for the pass.
More conventional, conceptually clearer, and instantly understandable way would be to include the template functions from a different files, say vsimple.impl:
#define USIZE 8
/* Generate vsenc8(), vsdec8()... */
#include "vsimple.impl"
#undef USIZE
#define USIZE 16
/* Generate vsenc16(), vsdec16()... */
#include "vsimple.impl"
#undef USIZE
#define USIZE 32
/* Generate vsenc32(), vsdec32()... */
#include "vsimple.impl"
#undef USIZE
#define USIZE 64
/* Generate vsenc64(), vsdec64()... */
#include "vsimple.impl"
The including file vsimple.c and the included file vsimple.impl could then also be organized to be much clearer in what they define and when. Most C programmers would recognize the implementational pattern and immediately know what is happening.
Recursively and repeatedly including itself this way invokes a feel of hocus-pocery which would attract applauds for an obfuscated C competition entry but not for mission critical production code.
It is recursion. Recursion is useful here because C preprocessing doesn't have looping. Moreover, it's desirable to perpetrate a trick using one file rather than proliferating multiple files.
Suppose you were required to write a function which interpolates the integers from 1 to 5 into a template string, and prints that on standard output. Suppose you were required to write exactly one function and were prohibited from loops, or copy-pasted printf statements. You might do this:
void template_print(const char *fmt, int n)
{
if (n == 0) {
template_print(fmt, 1);
template_print(fmt, 2);
template_print(fmt, 3);
template_print(fmt, 4);
template_print(fmt, 5);
} else {
/* imagine there are 30 lines of statements here we don't want
to repeat five times. */
printf(fmt, n);
}
}
The top-level call to this is then template_print("whatever %d\n", 0) distinguished by the zero argument of the n parameter.
The top-level call with 0 is like the initial processing of vsimple.c without USIZE being defined.
The requirement for one function is analogous to being required to produce a single, self-contained .c file rather than an "interface" file which #includes an implementation.
Why doesn't the following work when using double (it works using int)
test.c
#include "myFcn.h"
#include <stdio.h>
int main () {
printf("L1: %f \n", myGet_L1());
mySet_L1(10.0);
printf("L1: %f \n", myGet_L1());
return 0;
}
myFcn.c
#include "myFcn.h"
double L1 = 0.0;
double get(double *v) {
return *v;
}
void set(double *variable, double value) {
*variable = value;
}
myFcn.h
#ifndef __MYFCN_H__
#define __MYFCN_H__
extern double L1;
#define myGet_L1() get(&L1)
#define mySet_L1(value) set(&L1, (value))
#endif
I don't see why this is working when using int but not doubles?
First a comment: enable compiler warnings! That way, you might have found the answer yourself:
Your compilation unit for test.c misses prototypes for your get() and set(), so they're implicitly assumed to be
int get();
int set();
Which means they take an unspecified number of arguments (promoted to int) and return an int. This happens to generate some working code if you really use int for your L1, but doesn't work with double.
Solution: Declare your functions in the header file:
#ifndef __MYFCN_H__
#define __MYFCN_H__
extern double L1;
double get(double *);
void set(double *, double);
#define myGet_L1() get(&L1)
#define mySet_L1(value) set(&L1, (value))
#endif
Other notes:
With the code you provide, there's on the other hand no reason at all to have the variable itself visible to other compilation units, so better remove the line
extern double L1;
identifiers starting with underscores are reserved (see this answer for the complete rules), so the naming of your guard macro is not wise. Just use MYFCN_H instead.
In CCS6 I couldn't run this program properly.
typedef volatile struct{
unsigned int pin_in;
unsigned int pin_out;
unsigned int pin_dir;
unsigned int pin_ren;
unsigned int pin_ds;
unsigned int pin_sel;
unsigned int reserved[10];
}io_hw_t;
//#define PABASE ((io_hw_t*) (0x200)) // this part is working
#define PABASE 0x200
#define PBBASE 0x220
io_hw_t *const io[] = {PABASE, PBBASE}; // error
The warning I get is:
" #145-D a value of type "int" cannot be used to initialize an entity
of type "io_hw_t *const "
How can I fix this ?
Provide explicit casting in initialization as:
io_hw_t *const io[] = {(io_hw_t *)PABASE, (io_hw_t *)PBBASE};
io is declared as as array of const pointer to io_hw_t. So each member must be a pointer. But PABASE is integer constant and needs to be explicitly casted to pointer.
Alternatively you can add the casts in your macros also as:
#define PABASE ((void *)0x200)
After some work on the generic vector I asked about on this question, I would like to know if there is any way of checking that each instanciation of the library is only done once per type.
Here is what the current header file looks like:
#ifndef VECTOR_GENERIC_MACROS
#define VECTOR_GENERIC_MACROS
#ifndef TOKENPASTE
#define TOKENPASTE(a, b) a ## b
#endif
#define vector_t(T) TOKENPASTE(vector_t_, T)
#define vector_at(T) TOKENPASTE(*vector_at_, T)
#define vector_init(T) TOKENPASTE(vector_init_, T)
#define vector_destroy(T) TOKENPASTE(vector_destroy_, T)
#define vector_new(T) TOKENPASTE(vector_new_, T)
#define vector_delete(T) TOKENPASTE(vector_delete_, T)
#define vector_push_back(T) TOKENPASTE(vector_push_back_, T)
#define vector_pop_back(T) TOKENPASTE(vector_pop_back_, T)
#define vector_resize(T) TOKENPASTE(vector_resize_, T)
#define vector_reserve(T) TOKENPASTE(vector_reserve_, T)
#endif
typedef struct {
size_t size;
size_t capacity;
TYPE *data;
} vector_t(TYPE);
inline TYPE vector_at(TYPE)(vector_t(TYPE) *vector, size_t pos);
void vector_init(TYPE)(vector_t(TYPE) *vector, size_t size);
void vector_destroy(TYPE)(vector_t(TYPE) *vector);
inline TYPE *vector_new(TYPE)(size_t size);
inline void vector_delete(TYPE)(vector_t(TYPE) *vector);
void vector_push_back(TYPE)(vector_t(TYPE) *vector, TYPE value);
inline TYPE vector_pop_back(TYPE)(vector_t(TYPE) *vector);
inline void vector_resize(TYPE)(vector_t(TYPE) *vector, size_t size);
void vector_reserve(TYPE)(vector_t(TYPE) *vector, size_t size);
The header can then be included along with the source definitions:
#include <stdio.h>
#define TYPE int
#include "vector.h"
#include "vector.def"
#undef TYPE
int main()
{
vector_t(int) myVectorInt;
vector_init(int)(&myVectorInt, 0);
for (int i = 0; i < 10; ++i)
vector_push_back(int)(&myVectorInt, i);
for (int i = 0; i < myVectorInt.size; ++i)
printf("%d ", ++vector_at(int)(&myVectorInt, i));
vector_destroy(int)(&myVectorInt);
return 0;
}
I would like to make sure that the content below that last endif is only included once per TYPE.
Obviously, #ifdef VECTOR_INSTANCE(TYPE) does not work, so I'm really out of ideas...
It's a though question, however, I was also interested in the matter when I asked a similar question to yours some time ago.
My conclusions is that if you are going to use vectors (or, using more accurate naming, dynamic arrays) of many different types then it's wasteful to have all those functions vector_##TYPE##_reserve(), vector_##type##_resize(), etc... multiple times.
Instead, it is more efficient and clean to have those functions defined only once in a separate .c file, using your type's size as an extra argument. Those functions prototyped in a separate .h file. Then the same .h file would provide macros that generate functions wrappers for your own types, so that you don't see it using the size as an extra argument.
For example, your vector.h header would contain the following :
/* Declare functions operating on a generic vector type */
void vector_generic_resize(void *vector, size_t size, size_t data_size);
void vector_generic_push_back(void *vector, void *value, size_t data_size);
void *vector_generic_pop_back(void *vector, size_t data_size);
void vector_generic_init(void *vector, size_t size, size_t data_size);
void vector_generic_destroy(void *vector) ; // I don't think data_size is needed here
/* Taken from the example in the question */
#define VECTOR_DEFINITION(type)\
typedef struct {\
size_t size;\
size_t capacity;\
type *data;\
} vector_ ## type ## _t;\
/* Declare wrapper macros to make the above functions usable */
/* First the easy ones */
#define vector_resize(vector, size) vector_generic_resize(vector, size, sizeof(vector.data[0]))
#define vector_init(vector, size) vector_generic_init(vector, size, sizeof(vector.data[0]))
/* Type has to be given as an argument for the cast operator */
#define vector_pop_back(vector, type) (*(type*)(vector_generic_pop_back(vector, sizeof(vector.data[0]))))
/* This one is tricky, if 'value' is a constant, it's address cannot be taken.
I don't know if any better workarround is possible. */
#define vector_push_const(vector, type, value) \
{ \
type temp = value; \
vector_generic_push_back(vector, &temp, sizeof(vector.data[0]));\
}
/* Equivalent macro, but for pushing variables instead of constants */
#define vector_push_var(vector, value) vector_generic_push_back(vector, &value, sizeof(vector.data[0]))
/* Super-macro rediriging to constant or variable version of push_back depending on the context */
#define GET_MACRO(_1,_2,_3,NAME,...) NAME
#define vector_push_back(...) GET_MACRO(__VA_ARGS__, vector_push_const, vector_push_var)(__VA_ARGS__)
/* This macro isn't really needed, but just for homogenity */
#define vector_descroy(vector) vector_generic_destroy(vector)
The functions can then be used as you said in the example you linked, with the significant exception of vector_generic_push_back where unfortunately the type has to be specified each time as an extra macro argument.
So with this solution
You only have to do VECTOR_DEFINITION() within the .c file, avoiding the risk of declaring it with the same type twice
The vector library is only existing once in the binary
The macros can be used elegantly without using the type in their names, except for the pop back macro and the push literal macro.
If this is a problem you could make the push literal use long long always, it will work but potentially loose efficiency.
Similarly you could make the pop_back() macro and the vector_generic_pop_back() functions not return anything like they does in the C++ language, so that if you do both of those tricks you never need to use the type name explicitly in the macros.
As a reference, the main function you posted in the example that is linked in your question has to be adapted like that :
#include <stdio.h>
#include <stdlib.h>
#include "vector.h"
typedef unsigned int uint;
typedef char* str;
VECTOR_DEFINITION(uint)
VECTOR_DEFINITION(str)
int main()
{
vector_uint_t vector;
vector_init(&vector, 10);
for (unsigned int i = 0; i < vector.size; ++i)
vector.data[i] = i;
for (unsigned int i = 0; i < 10; ++i)
vector_push_back(&vector, i);
/* When pushing back a constant, we *have* to specity the type */
/* It is OK to use C keywords as they are supressed by the preprocessor */
vector_push_back(&vector, unsigned int, 12);
for (unsigned int i = 0; i < vector.size; ++i)
printf("%d ", vector.data[i]);
printf("\n");
vector_destroy(&vector);
vector_str_t sentence;
vector_init(&sentence, 0);
vector_push_back(&sentence, "Hello");
vector_push_back(&sentence, str, "World!"); /* Also possible, less efficient */
vector_push_back(&sentence, "How");
vector_push_back(&sentence, "are");
vector_push_back(&sentence, "you?");
for (unsigned int i = 0; i < sentence.size; ++i)
printf("%s ", sentence.data[i]);
printf("\n");
vector_destroy(&sentence);
return 0;
}
suggest:
remove the prototypes from the vector.h file.
place the prototypes at the top of the vector.def file.
remove the typedef struct from the vector.h file
place the typedef struct before the prototypes in the vector.def file.
then multiples #include statements for the vector.h file will have no bad effects.
Then use the following, in each source file that is to use these vector types:
#include<vector.h>
#define TYPE int
#include<vector.def>
#undef TYPE
#define TYPE char
#include<vector.def>
#undef TYPE
... etc
BTW:
There is no library involved, so I'm a bit confused by the reference
to 'library' in the question
It may be worthwhile to also prefix the 'static' modifier
to each of the function definitions so the definitions are
not visible across source files
It may be worthwhile to use parens around the parameters to TOKENPASTE
so modifiers like 'static' and.or 'const'
can be prefixed to the function names.
I have a requirement that states a function should take in one new argument at the beginning of the argument list for a new platform I am working on.
so the following would be a prototype for this new platform
void foo (int newarg, const char * a, int b, int c);
where as in the previous case it was just
void foo (const char * a, int b, int c);
My concern is readability and code space . So I am thinking of using ifdefs but i am not sure if it is a good idea to use if def with in a argument list.
1)
void foo (
#ifdef __NEWPLATFORM__
int newarg,
#else
const char * a, int b, int c
#endif
);
or
#if __NEWPALTFORM__
void foo (int newarg, const char * a, int b, int c);
#else
void foo (const char * a, int b, int c);
#endif
Btw I cannot put the new argument to the end of the list which would make it a lot easier.
Which one of the two (or maybe a better solution) is better?
Thanks
Given that you are changing all the calls to foo,
just change foo to the function with more parameters, then #ifdef internal to the function for different functionality.
void foo (int newarg, const char * a, int b, int c){
#ifdef __NEWPALTFORM__
#else
#endif
}
Also worth considering whether the parameters to the function should really be a struct, in which case new parameters in the future won't be much of an issue. Not enough context in your question to say whether this is a good idea or not
but it would be something like :=
typedef struct {
int newarg;
const char* a;
int b;
int c;
} fooType;
void foo(fooType f) // either by value or by pointer depending on context
{
// #ifdefs...
}
A third option would be to conditionally define a symbol for the extra argument. You might use the #ifdef section to include other useful platform related stuff, for example:
#ifdef MY_NEW_PLATFORM
#define EXTRA_ARGS int newarg,
#define GET_EXTRA newarg
#define SET_EXTRA(val) newarg = (val)
#else
#define EXTRA_ARGS
#define GET_EXTRA 0
#define SET_EXTRA(val)
#endif
...
void foo (EXTRA_ARGS const char * a, int b, int c) {
b = GET_EXTRA + c; /* Just as example */
SET_EXTRA(b+c);
}
As you can see, the foo function has no distracting "#ifdefs", and it compiles in any platform.