I have an array (C language) that should be initialized at compile time.
For example:
DECLARE_CMD(f1, arg);
DECLARE_CMD(f2, arg);
The DECLARE_CMD is called from multiple files.
I want this to be preprocessed in.
my_func_type my_funcs [] = {
&f1,
&f2
}
It is possible, with a macro, to append items to an static array?
I am using C99 (with GNU extensions) on gcc4.
Yes, you can build dynamic arrays at compile time (not at runtime) (and thank's to Mitchel Humpherys), the idea is to declare your callbacks in the same section like this:
EXAMPLE:
Suppose you have three files a.c, b.c main.c and i.h
into i.h
typedef void (*my_func_cb)(void);
typedef struct func_ptr_s {
my_func_cb cb; /* function callback */
} func_ptr_t;
#define ADD_FUNC(func_cb) \
static func_ptr_t ptr_##func_cb \
__attribute((used, section("my_array"))) = { \
.cb = func_cb, \
}
into a.c
#include "i.h"
static void f1(void) {
....
}
ADD_FUNC(f1);
into b.c
#include "i.h"
static void f2(void) {
....
}
ADD_FUNC(f2);
into main.c
#include "i.h"
static void f3(void) {
....
}
ADD_FUNC(f3);
#define section_foreach_entry(section_name, type_t, elem) \
for (type_t *elem = \
({ \
extern type_t __start_##section_name; \
&__start_##section_name; \
}); \
elem != \
({ \
extern type_t __stop_##section_name; \
&__stop_##section_name; \
}); \
++elem)
int main(int argc, char *argv[])
{
section_foreach_entry(my_array, func_ptr_t, entry) {
entry->cb(); /* this will call f1, f2 and f3 */
}
return 0;
}
IMPORTANT
sometimes the compiler optimizes start/end sections variables, it wipes them out, so when you try to use them, you will have a linker error: error LNK2019: unresolved external symbol ...
to fix this problem, i use the following:
Try to print your linker script:
gcc -Wl,-verbose
copy the text between the two:
==================================================
in a file (example lnk.lds), you should see thing like:
/* Script for -z combreloc: combine and sort reloc sections */
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64","elf64-x86-64")
........
ADD your section to the linker script file lnk.lds after the section .data like this (my defined section is called my_array as in the example):
__start_my_array = .;
.my_array :
{
*(.my_array)
}
__stop_my_array = .;
Compile your program with the updated linker script like this:
gcc -O3 -Xlinker -T"lnk.lds" file.c -o program
If you type strings program | grep "__start_my_array" you should find it.
NOTE: in your question there are semicolons at the end of every line. This will seriously interfere with any attempt to use these macros. So it depends on where and how the DECLARE_CMD(...) lines are found, and whether you can fix the semicolon problem. If they are simply in a dedicated header file all by themselves, you can do:
#define DECLARE_CMD(func, arg) &func,
my_func_type my_funcs [] {
#include "file_with_declare_cmd.h"
};
...which gets turned into:
my_func_type my_funcs [] {
&f1,
&f2,
};
Read The New C: X Macros for a good explanation of this.
If you can't get rid of the semicolons, this will be processed to:
my_func_type my_funcs [] {
&f1,;
&f2,;
};
... which is obviously a syntax error, and so this won't work.
Yes, it is possible.
The usual trick is to have all the DECLARE_CMD(func, args) lines in one (or more) include files, and to include those in various places with an appropriate definition for the macro.
For example:
In file 'commands.inc':
DECLARE_CMD(f1, args)
DECLARE_CMD(f2, args)
In some source file:
/* function declarations */
#define DECLARE_CMD(func, args) my_func_type func;
#include "commands.inc"
#undef DECLARE_CMD
/* array with poiners */
#define DECLARE_CMD(func, args) &func,
my_func_type* my_funcs[] = {
#include "commands.inc"
NULL
};
You can actually use a single macro to set the function pointers, do the function declaration, set up enums to access the function pointer and strings to use in error messages and later you can use it in a switch().
#define X_MACRO(OP) \
OP(addi, int x, int y) \
OP(divi, int x, int y) \
OP(muli, int x, int y) \
OP(subi, int x, int y)
#define AS_FUNC_PTR(x,...) x,
#define AS_FUNC(x,...) int x(__VA_ARGS__);
#define AS_STRINGS(x,...) #x,
#define AS_ENUMS(x,...) ENUM_##x,
X_MACRO(AS_FUNC)
typedef int (*foo_ptr_t)( int, int );
foo_ptr_t foo[] = { X_MACRO(AS_FUNC_PTR) };
char *foo_strings[] = { X_MACRO(AS_STRINGS) };
enum foo_enums { X_MACRO(AS_ENUMS) };
/** example switch()
#define AS_CASE(x,...) ENUM_x : x(i,j);break;
switch (my_foo_enum){
X_MACRO(AS_CASE)
default: do_error();
}
**/
Related
Simple idea:
I'm using X-macros to define command list structure and declare command callbacks.
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#define COMMAND_LIST(X) \
X(toto_all) \
X(help) \
//end of list
typedef void (*callback_t)(int a, int b);
typedef struct
{
char * name;
callback_t callback;
}command_t;
#define CALLBACK_DEC(COMMAND_NAME) void _##COMMAND_NAME(int a, int b);
COMMAND_LIST(CALLBACK_DEC)
#define COMMAND_DEF(COMMAND_NAME) { #COMMAND_NAME, & _##COMMAND_NAME },
static command_t commands[] =
{
COMMAND_LIST(COMMAND_DEF)
};
#define COMMAND(COMMAND_NAME,CODE) void _##COMMAND_NAME(int A, int B) { CODE }
COMMAND(toto_all,
printf("helloworld\n");
)
COMMAND(help,
printf("help!\n");
)
int main()
{
commands[0].callback(1,2);
commands[1].callback(1,2);
return 0;
}
it works.
helloworld
help!
Adding some parameters:
If you change the first command list to this (by adding parameters)
#define COMMAND_LIST(X) \
X(toto_all, 1, 3, 5) \
X(help, 0, 0, 0) \
//end of list
typedef struct
{
callback_t callback;
char * name;
int arg_min;
int arg_max;
int arg_num;
}command_t;
then, when running it I get the following error:
macro "CALLBACK_DEC" passed 4 arguments, but takes just 1
I have to use all the parameters for the command list definition (command declaration):
#define COMMAND_DEF(COMMAND_NAME, ARG_MIN, ARG_MAX, ARG_MAX, ARG_NUM) (command_t){ #COMMAND_NAME, & _##COMMAND_NAME, ARG_MIN, ARG_MAX, ARG_NUM},
but it's quite tricky to now use it for the callback declaration...
Is there a clever way for this X-macro to avoid this error?
I thought about the non-macro way to mask unused parameters:
which is by using (void)param;,
which gives the ugly
#define CALLBACK_DEC(COMMAND_NAME, ARG_MIN, ARG_MAX, ARG_NUM) void _##COMMAND_NAME(int a, int b); void(ARG_MIN); void(ARG_MAX); void(ARG_NUM)
and this does not work...I get a strange:
main.c:27:20: error: expected identifier or ‘(’ before numeric constant
X(toto_all,0,0,0) \
I think there is another way:
maybe using something like this...
#define COMMAND_LIST(X,Y) \
X(Y(toto_all, 0, 0, 0)) \
X(Y(help, 0, 0, 0)) \
//command name, arg min, arg max, arg num, string?
//end of list
typedef void (*callback_t)(int a, int b);
typedef struct
{
char * name;
callback_t callback;
}command_t;
#define GET_ONLY_NAME(COMMAND_NAME1, ARG_MIN, ARG_MAX, ARG_NUM) COMMAND_NAME1
#define CALLBACK_DEC(COMMAND_NAME) void _##COMMAND_NAME(int a, int b);
COMMAND_LIST(CALLBACK_DEC,GET_ONLY_NAME);
#undef CALLBACK_DEC
#define GET_FULL_LIST(X) X
#define COMMAND_DEF(COMMAND_NAME, ARG_MIN, ARG_MAX, ARG_NUM) (command_t){ #COMMAND_NAME, & _##COMMAND_NAME, ARG_MIN, ARG_MAX, ARG_NUM},
static command_t commands[] =
{
COMMAND_LIST(COMMAND_DEF,GET_FULL_LIST)
};
#undef COMMAND_DEF
but I still get the following strange error, there is a problem in the expansion but i can't see where...
main.c:27:31: error: expected ‘)’ before numeric constant
X(Y(toto_all, 0, 0, 0)) \
Maybe the truth is elsewhere... :)
any hints?
This is a an issue with X macros overall - you have to write a macro accepting all parameters, even when you are just using a few.
In your case you pass the specific macro as a parameter to the list, so you can add some flexibility there. Using variadic macros might solve the problem. You should be able to do like this:
#define COMMAND_DEF(COMMAND_NAME, ...) { #COMMAND_NAME, & _##COMMAND_NAME },
...
COMMAND_LIST(COMMAND_DEF)
Where you only explicitly name the parameters that this particular macro is interested in, then let the rest of them go into the ... part which is then ignored.
This does however build in a dependency in the data, because it only allows you to expand parameters from left to right, so to speak. So for
X(toto_all, 1, 3, 5, "-")
you can write a macro that uses just toto_all, or toto_all and 1, but you would't be able write a macro that just uses for example 1 and 3. For such special cases I believe you will still have to name all macro parameters.
Yet another option is self-documenting code:
#define COMMAND_DEF(COMMAND_NAME, ignored1, FOO, ignored2, ignored3) \
/* do stuff with COMMAND NAME and FOO only */
Let's say I have moduleA.c moduleB.c and moduleC.c, and modules B and C need to read variables from moduleA.h, but I want to prevent them from write these variables, only A can.
After looking for a while, the only solution I found would be to use "get" functions, but I certainly have many of those variables. Is there any faster way than creating a "get" function for each variable?
Export pointers to those variables and make them const.
//moduleA.h
extern const type* const c;
//moduleA.c
type t;
const type* const c = &t;
type* p = &t;
Module A can read the object either through t, c, or p, and can modify it through t and p, while other modules can only read it through c.
You can do this with implementing properties with C preprocessor macros.
I will start with something you presumably have now — variable access without any restrictions. peek and poke functions are provided as an example to reflect how are we reading and writing these properties.
// module_a.h
//
#ifndef __MODULE_A__H__
#define __MODULE_A__H__
void poke(void);
void *foo;
int bar;
float buzz;
#endif
// module_a.c
//
#include "module_a.h"
void poke(void) {
foo = (void*) 0xDEADBABE;
bar = 314;
buzz = 2.71828f;
}
// module_b.h
//
#ifndef __MODULE_B__H__
#define __MODULE_B__H__
void peek(void);
#endif
// module_b.c
//
#include <stdio.h>
#include "module_b.h"
#include "module_a.h"
void peek(void) {
printf("%p, %d, %f\n", foo, bar, buzz);
}
Now we are going to hide these variables from other modules by moving variable declarations inside module_a.c, and declaring them as static to change their linkage to internal. Static declarations are only visible within the translation unit they were declared in (e.g. module_a.c and everything it includes).
To allow other modules to access these variables, we would create few macros to define and declare getters for each property.
// module_a.h
//
#ifndef __MODULE_A__H__
#define __MODULE_A__H__
void poke(void);
#define DECL_PROP(T, name) \
T get_##name(void);
#define DEF_PROP(T, name) \
T get_##name(void) { \
return name; \
}
DECL_PROP(void*, foo);
DECL_PROP(int, bar);
DECL_PROP(float, buzz);
#endif
// module_a.c
//
#include "module_a.h"
static void *foo;
static int bar;
static float buzz;
DEF_PROP(void*, foo);
DEF_PROP(int, bar);
DEF_PROP(float, buzz);
void poke(void) {
foo = (void*) 0xDEADBABE;
bar = 314;
buzz = 2.71828f;
}
// module_b.c
//
#include <stdio.h>
#include "module_b.h"
#include "module_a.h"
void peek(void) {
printf("%p, %d, %f\n", get_foo(), get_bar(), get_buzz());
}
However, these macros seem to be self-repeating a lot — we have mentioned each of properties three times — twice in the implementation and once in the interface part. Maintaining such construct is very error prone, so let's try to reduce this number by combining getter definition and variable declaration.
// module_a.h
//
#ifndef __MODULE_A__H__
#define __MODULE_A__H__
void poke(void);
#define DECL_PROP(T, name) \
T get_##name(void);
#define DEF_PROP(T, name) \
static T name; \
\
T get_##name(void) { \
return name; \
}
DECL_PROP(void*, foo);
DECL_PROP(int, bar);
DECL_PROP(float, buzz);
#endif
// module_a.c
//
#include "module_a.h"
DEF_PROP(void*, foo);
DEF_PROP(int, bar);
DEF_PROP(float, buzz);
void poke(void) {
foo = (void*) 0xDEADBABE;
bar = 314;
buzz = 2.71828f;
}
Now let's reduce this further by combining property definition and declaration together and moving our property macros to separate file to keep module files clean and beautiful.
// props.h
//
#ifndef __PROPS__H__
#define __PROPS__H__
#define _DECL_PROP(T, name) \
T get_##name(void);
#define _DEF_PROP(T, name) \
static T name; \
\
T get_##name(void) { \
return name; \
}
#define DECL_PROPS(PROPSET) \
PROPSET(_DECL_PROP)
#define DEF_PROPS(PROPSET) \
PROPSET(_DEF_PROP)
#endif
// module_a.h
//
#ifndef __MODULE_A__H__
#define __MODULE_A__H__
#include "props.h"
void poke(void);
#define I_WANT_MY_PROPS(_) \
_(void*, foo); \
_(int, bar); \
_(float, buzz);
DECL_PROPS(I_WANT_MY_PROPS)
#endif
// module_a.c
//
#include "module_a.h"
DEF_PROPS(I_WANT_MY_PROPS)
void poke(void) {
foo = (void*) 0xDEADBABE;
bar = 314;
buzz = 2.71828f;
}
Now, as a final touch, let's add private setters for these properties and obfuscate names of underlying variables so they would not be accessible directly.
// props.h
//
#ifndef __PROPS__H__
#define __PROPS__H__
#define _PROP_VAR_NAME(name) \
_private_property_prefix_##name
#define _DECL_PROP(T, name) \
T get_##name(void);
#define _DEF_PROP(T, name) \
static T _PROP_VAR_NAME(name); \
\
T get_##name(void) { \
return _PROP_VAR_NAME(name); \
} \
\
static inline T set_##name(T value) { \
_PROP_VAR_NAME(name) = value; \
\
return value; \
}
#define DECL_PROPS(PROPSET) \
PROPSET(_DECL_PROP)
#define DEF_PROPS(PROPSET) \
PROPSET(_DEF_PROP)
#endif
// module_a.c
//
#include "module_a.h"
DEF_PROPS(I_WANT_MY_PROPS)
void poke(void) {
set_foo((void*) 0xDEADBABE);
set_bar(314);
set_buzz(2.71828f);
}
There are many schemes you could use. However, the simplest is allow read/write access from everywhere.
To enforce that only writes can occur in moduleA, look at all the code: make sure that only moduleA is writing and all other modules either don't access it, or only read from the variable.
If you have code like
int var1;
char * var2;
// ...
double var20;
where all these varX are global variables, then you really should start refactoring them away.
One possible (although almost equally "dirty") approach is to combine them in some configuration structure and to only provide a "get" function for this structure.
Of course, if you're only concerned about the time / code it takes to create a get function, well, then I welcome you to the evil magic of the preprocessor:
#define DECLARE_GLOBAL(type, name) \
extern type name; \
type get_ ## name(void);
#define DEFINE_GLOBAL(type, name, initial) \
type name = initial; \
type get_ ## name(void) { return name; }
In your header:
DECLARE_GLOBAL(int, var1);
In your implementation file:
DEFINE_GLOBAL(int, var1, 42);
Try this at home, but don't consider it as good practice.
I'm trying to work through an issue on a third party library. The issue is the library uses GCC's nested functions buried in a macro, and Clang does not support nested functions and has no plans to do so (cf., Clang Bug 6378 - error: illegal storage class on function).
Here's the macro that's the pain point for me and Clang:
#define RAII_VAR(vartype, varname, initval, dtor) \
/* Prototype needed due to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36774 */ \
auto void _dtor_ ## varname (vartype * v); \
void _dtor_ ## varname (vartype * v) { dtor(*v); } \
vartype varname __attribute__((cleanup(_dtor_ ## varname))) = (initval)
And here's how its used (from the code comments):
* void do_stuff(const char *name)
* {
* RAII_VAR(struct mything *, thing, find_mything(name), ao2_cleanup);
* if (!thing) {
* return;
* }
* if (error) {
* return;
* }
* do_stuff_with_thing(thing);
* }
The Clang User Manual states to use C++ and a lambda function to emulate. I'm not sure that's the best strategy, and a C project will likely not accept a C++ patch (they would probably tar and feather me first).
Is there a way to rewrite the macro so that's its (1) more accommodating to Clang, and (2) preserves original function semantics?
Clang doesn't support GCC nested functions, but it does support Objective C-style "blocks", even in C mode:
void f(void * d) {
void (^g)(void *) = ^(void * d){ };
g(d);
}
You need to invoke it with the clang command rather than gcc, and also (?) pass -fblocks -lBlocksRuntime to the compiler.
You can't use a block as a cleanup value directly, since it has to be a function name, so (stealing ideas from here) you need to add a layer of indirection. Define a single function to clean up void blocks, and make your RAII'd variable the block that you want to run at the end of the scope:
typedef void (^cleanup_block)(void);
static inline void do_cleanup(cleanup_block * b) { (*b)(); }
void do_stuff(const char *name) {
cleanup_block __attribute__((cleanup(do_cleanup))) __b = ^{ };
}
Because blocks form closures, you can then place the operations on your variables to cleanup directly inside that block...
void do_stuff(const char *name) {
struct mything * thing;
cleanup_block __attribute__((cleanup(do_cleanup))) __b = ^{ ao2_cleanup(thing); };
}
...and that should run at the end of the scope as before, being invoked by the cleanup on the block. Rearrange the macro and add a __LINE__ so it works with multiple declarations:
#define CAT(A, B) CAT_(A, B)
#define CAT_(A, B) A##B
#define RAII_VAR(vartype, varname, initval, dtor) \
vartype varname = (initval); \
cleanup_block __attribute__((cleanup(do_cleanup))) CAT(__b_, __LINE__) = ^{ dtor(varname); };
void do_stuff(const char *name) {
RAII_VAR(struct mything *, thing, NULL, ao2_cleanup);
...
Something like that, anyway.
I believe you can do this without using a clang-specific version, I'd try something like this (untested, may require a few extra casts):
struct __destructor_data {
void (*func)(void *);
void **data;
}
static inline __destructor(struct __destructor_data *data)
{
data->func(*data->data);
}
#define RAII_VAR(vartype, varname, initval, dtor) \
vartype varname = initval; \
__attribute((cleanup(__destructor))) \
struct __destructor_data __dd ## varname = \
{ dtor, &varname };
In our project we have a gcc-specific _auto_(dtor) macro that precedes the normal variable declaration, e.g.:
_auto_(free) char *str = strdup("hello");
In this case our macro can't add anything after the variable declaration and also doesn't know the name of the variable, so to avoid using gcc-specific nested functions I came up with the following hackish version in case this helps anyone:
static void *__autodestruct_value = NULL;
static void (*__autodestruct_dtor)(void *) = NULL;
static inline void __autodestruct_save_dtor(void **dtor)
{
__autodestruct_dtor = *dtor;
__autodestruct_dtor(__autodestruct_value);
}
static inline void __autodestruct_save_value(void *data)
{
__autodestruct_value = *(void **) data;
}
#define __AUTODESTRUCT(var, func) \
__attribute((cleanup(__autodestruct_save_dtor))) \
void *__dtor ## var = (void (*)(void *))(func); \
__attribute((cleanup(__autodestruct_save_value)))
#define _AUTODESTRUCT(var, func) \
__AUTODESTRUCT(var, func)
#define _auto_(func) \
_AUTODESTRUCT(__COUNTER__, func)
This is hackish because it depends on the order the destructors are called by the compiler being the reverse of the order of the declarations, and it has a few obvious downsides compared to the gcc-specific version but it works with both compilers.
Building on the answers above, here's my hack to allow clang to compile nested procedures written in gcc-extension style. I needed this myself to support a source-to-source translator for an Algol-like language (Imp) which makes heavy use of nested procedures.
#if defined(__clang__)
#define _np(name, args) (^name)args = ^args
#define auto
#elif defined(__GNUC__)
#define _np(name, args) name args
#else
#error Nested functions not supported
#endif
int divide(int a, int b) {
#define replace(args...) _np(replace, (args))
auto int replace(int x, int y, int z) {
#undef replace
if (x == y) return z; else return x;
};
return a / replace(b,0,1);
}
int main(int argc, char **argv) {
int a = 6, b = 0;
fprintf(stderr, "a / b = %d\n", divide(a, b));
return 0;
}
struct Error
{
MACRO(1, Connect);
MACRO(2, Timeout);
};
I need to define MACRO() in such way that the above code will generate the following code.
struct Error
{
static const int Connect = 1;
static const int Timeout = 2;
const char * const name[] = {"Connect", "Timeout"};
};
Is this possible or what is the alternative to get what I'm trying to do?
You can't do this directly, but you can if you move the macros to a separate location (such as a separate file):
macros.hpp
MACRO(1, Connect)
MACRO(2, Timeout)
#undef MACRO
the other file
struct Error
{
#define MACRO(a, b) static const int b = a;
#include "macros.hpp"
const char * const name [] = {
#define MACRO(a, b) #b,
#include "macros.hpp"
}
};
Alternatively, you could achieve a similar effect with Boost.Preprocessor.
Here's a Boost.Preprocessor solution:
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/preprocessor/stringize.hpp>
#define FIRST(a, b) a
#define SECOND(a, b) b
#define DECLARE_VAR(r, data, elem) \
static const int FIRST elem = SECOND elem;
#define NAME_ARRAY_ELEM(r, data, elem) \
BOOST_PP_STRINGIZE(FIRST elem),
#define MACRO(seq) \
BOOST_PP_SEQ_FOR_EACH(DECLARE_VAR, ~, seq) \
const char * const name[] = { \
BOOST_PP_SEQ_FOR_EACH(NAME_ARRAY_ELEM, ~, seq) \
}
int main()
{
MACRO(((Connect, 1))((TimeOut, 2)));
return 0;
}
You have to make sure to double bracket each ((Token, value)) pair, however you don't need a separate file for your macro.
What you want, is to have a single list, that will automatically generate the definition and the name list, correct?
If so, search for X Macros in google.
Example:
#define EXPAND_AS_DEFINITION(a, b) static const int b = a;
#define EXPAND_AS_ARRAY(a, b) #b,
#define STATE_TABLE(ENTRY) \
ENTRY(1, Connect) \
ENTRY(2, Timeout)
struct Error
{
STATE_TABLE(EXPAND_AS_DEFINITION)
static const char * const name[];
};
const char * const Error::name[] = {STATE_TABLE(EXPAND_AS_ARRAY) 0};
It looks like like you are trying to define an enum Error that also has the strings as members. I will give you my own solution to this problem. (I'm not addressing the question but I believe that my answer is relevant for what I understand that OP is trying to do.)
And I just realized that OP is targeting C, not C++, so not sure if this can be done...
In MyEnum.hpp
#define MYENUM(X,...) \
struct X { \
enum Enum {__VA_ARGS__}; \
static const std::vector<std::string> names; \
static X::Enum which(const std::string& s) { \
return static_cast<X::Enum>(findEnum(s,names)); \
} \
static std::string str(X::Enum i) { \
return names[i];} \
}
Here findEnum() is just a linear search over the vector that returns the position index (additionally, in my implementation if it doesn't find it it throws an exception with all the possible correct inputs, I also do case insensitive comparison). Note that an ordered map instead of a vector would be more efficient (O(log(n)) instead of O(n)), but I didn't cared much because the size of those things is very small in my case.
Below the previous macro, declare your enum as
MYENUM(Error,Connect,Timeout); // I put the semicolon here not in the macro
And in MyEnum.cpp, add
#include <boost/assign/list_of.hpp>
const std::vector<std::string> Error::names = boost::assign::list_of
("Connect")("Timeout");
(I think that it should be possible to use initialization lists with a modern compiler). The important thing here is to make sure that the order is the same, otherwise it will not work.
Then, you can do stuff like this:
Error::Enum err1 = Error::Connect;
Error::Enum err2 = Error::which("Timeout");
std::cout << "Got " << Error::str(err1) << " error. Not good.\n";
I would like to do something like the following:
F_BEGIN
F(f1) {some code}
F(f2) {some code}
...
F(fn) {some code}
F_END
and have it generate the following
int f1() {some code}
int f2() {some code}
...
int fn() {some code}
int (*function_table)(void)[] = { f1, f2, ..., fn };
The functions themselves are easy. What I can't seem to do is to keep track of all of the names until the end for the function_table.
I looked at this question and this question but I couldn't get anything to work for me.
Any ideas?
The normal way of doing this with the preprocessor is to define all the functions in a macro that takes another macro as an argument, and then use other macros to extract what you want. For your example:
#define FUNCTION_TABLE(F) \
F(f1, { some code }) \
F(f2, { some code }) \
F(f3, { some code }) \
:
F(f99, { some code }) \
F(f100, { some code })
#define DEFINE_FUNCTIONS(NAME, CODE) int NAME() CODE
#define FUNCTION_NAME_LIST(NAME, CODE) NAME,
FUNCTION_TABLE(DEFINE_FUNCTIONS)
int (*function_table)(void)[] = { FUNCTION_TABLE(FUNCTION_NAME_LIST) };
If you have a C99 complying compiler, the preprocessor has variable length argument lists. P99 has a preprocessor P99_FOR that can do "code unrolling" like the one you want to achieve. To stay close to your example
#define MYFUNC(DUMMY, FN, I) int FN(void) { return I; }
#define GENFUNCS(...) \
P99_FOR(, P99_NARG(__VA_ARGS__), P00_IGN, MYFUNC, __VA_ARGS__) \
int (*function_table)(void)[] = { __VA_ARGS__ }
GENFUNCS(toto, hui, gogo);
would expand to the following (untested)
int toto(void) { return 0; }
int hui(void) { return 1; }
int gogo(void) { return 2; }
int (*function_table)(void)[] = { toto, hui, gogo };
This is sort of abuse of CPP but a common type of abuse. I handle situations
like this by defining dummy macros
#define FUNCTIONS \
foo(a,b,c,d) \
foo(a,b,c,d) \
foo(a,b,c,d)
now,
#define foo(a,b,c,d) \
a+b ;
FUNCTIONS
#undef foo
later, when you want something different done with the same list
#define foo(a,b,c,d) \
a: c+d ;
FUNCTIONS
#undef foo
It's a bit ugly and cumbersome, but it works.
There's this thing called X Macro which is used as:
a technique for reliable maintenance of parallel lists, of code or data, whose corresponding items must appear in the same order
This is how it works:
#include <stdio.h>
//you create macro that contains your values and place them in (yet) not defined macro
#define COLORS\
X(red, 91)\
X(green, 92)\
X(blue, 94)\
//you can name that macro however you like but conventional way is just an "X"
//and then you will be able to define a format for your values in that macro
#define X(name, value) name = value,
typedef enum { COLORS } Color;
#undef X //so you redefine it below
int main(void)
{
#define X(name, value) printf("%d, ", name);
COLORS
#undef X
return 0;
}
Solution for your problem would be:
#define FUNCTIONS \
F(f1, code1)\
F(f2, code2)\
F(f3, code3)
#define F(name, code) int name(void){code}
FUNCTIONS
#undef F
#define F(name, code) &name,
int (*function_table[])(void) = { FUNCTIONS };
#undef F
Boost is a C++ library, but it's Preprocessor module should still be good for use in C. It offers some surprisingly advanced data types and functionality for use in the preprocessor. You could check it out.