I want to simplify things, by not creating a list of enum separately, but create the enums along the function call which creates the data where i point with those enums.
I tried to make #define which would create another #define, but it didnt work:
int defcounter = 0;
#define make_def(enumname, somedata) \
#define enumname defcounter \
defcounter++; \
func_call(somedata); \
void createstuff(){
make_def(MY_ENUM_NAME, mydata);
make_def(MY_OTHER_ENUMNAME, mydata);
}
void dostuff(){
somefunc_call(MY_ENUM_NAME);
somefunc_call(MY_OTHER_ENUMNAME);
}
But this will create error at the #define enumname:
error C2162: expected macro formal parameter
How can I make this work?
It is impossible to create new types (classes, enums, unions, whatever) at runtime in C++. One of the major features of C++ is that it is statically typed - all types must be known at compile time.
Preprocessor commands (#define, #if, #pragma, #include, ...) cannot appear in macros / defines. The problem is, that the CPP (C-Preprocessor) seperates commands by newlines, while C and C++ are unaware of newlines. In C/C++ you can write everything on one line, for preprocessor commands, you can't.
#define MY_MACRO(name) \
#define name##_macro something_cool \
enum name{ \
.... \
}
// somewhere else
void myfunc(){
MY_MACRO(myfunc_enum);
}
Now, at preprocessing time, those lines all get glued into one big line, thanks to the \ backslash:
#define MY_MACRO(name) #define name##_macro something_cool enum name{....}
Now, how would that macro look at usage?
void myfunc(){
#define name##_macro something_cool enum name{....};
}
Now, the preprocessor has to run over that #define again. But exactly what belongs to the #define, and what doesn't? For the coder it was clear when the macro was written in seperate lines, but now it isn't anymore.
What exactly is your desired output? You need to explain what you think you might get as output from the C preprocessor.
You have scope problems and an attempt to define a macro inside the replacement text of another macro.
Scope
The macro make_def() invokes an undefined function 'func_call'. The createstuff() function uses an undefined variable mydata. And function dostuff() seems to call an undefined function somefunc_call() with an enum that might, perhaps, have been defined inside a separate function.
If an enumeration is defined inside one function, that enumeration is not available to code outside that function, and specifically is not available to either called functions or calling functions. That alone limits the utility of what you seem to be attempting to do. (Yes, the enumeration values might be implicitly converted to int or some similar type, but it is not really the enumeration type that is being used.)
Defining macros in macros
You cannot create a macro that itself contains #define or any other preprocessor directive in its replacement text.
If the outer macro is invoked, the expansion does not interpret the inner #define as being a preprocessor directive, so it almost always ends up as an error, In context the # must be a stringize operator, and the word 'define' after it would have to be the name of an argument to the outer macro to have a chance of working.
// Does not work as intended
#define macro(define, prefix) #define another(name) foo(prefix ## name)
macro(something, other);
Generates:
"something" another(name) foo(othername);
The _Pragma in C99 is a partial exception to the 'a macro expansion cannot contain a preprocessor directive', but it (_Pragma) does not start with #.
Your macro is incorrect, since you cannot use a macro to create another macro, unfortunately, as the toke # has special meaning in the expansion-list: it can either quote a macro argument, or expand another macro. One easy (albeit poorly designed) way you could do this is just to use old c-style #define MY_ENUM_NAME valueas c macro do not respect scope, but this would not be good design. Another possibility is to pass in string arguments and hash on them, but all depends on what you want to do.
Related
There are lots of tutorials and quesitons addressing this. But I want to confirm my understanding in one specific case. The two below should not make a difference to the compiler i.e either one is correct. Right?
typedef _GridLayoutInputRepeater<_num-1,Figure,_types...> _base;
and
#define _base _GridLayoutInputRepeater<_num-1,Figure,_types...>
Similarly , the below should not make the difference?
#define INT_32 uint32_t
and
typedef uint32_t INT_32;
EDIT : Follow up thread here
Currently without showing use-cases the 2 situations are both "equal" but what you should note is that #define is a whole different beast than typedef.
typedef introduces an alias for another type, this alias will be seen by the compiler and thus will follow compiler rules, scoping etc.
A #define is a preprocessor macro, the preprocessor will run before the actual compiler and will literally do a textual replacement, it does not care about scoping or any syntax rules, it's quite "dumb".
Usually, typedefs are the way to go as they are so much less error-prone. In which case you could use using = as well but that's personal preference since they're both the same:
using _base = _GridLayoutInputRepeater<_num-1,Figure,_types...>;
The problem with using #define rather than typedef or using is that [as has been pointed out] #define is a macro, and macros are evaluated and expanded by the preprocessor, so the compiler knows nothing about the data type you're trying to create because the #define directive is simply substituted with whatever comes after it.
The reason for using macros in languages such as C and C++ is to allow for things that aren't specifically to do with source code logic but are to do with source code structure.
The #include directive, for instance, quite literally includes the entire content of a file in place of the derective.
So, if myfile.h contains:
void func_1(int t);
void func_2(int t);
then
#inlude "myfile.h"
would expand the content of myfile.h, replacing the #include preprocessor directive with
void func_1(int t);
void func_2(int t);
The compiler then comes along and compiles the expanded file with class definitions, and other expanded macros!
It's why the macro
#pragma once
or
#ifndef __MYFILE_INCLUDE__
#define __MYFILE_INCLUDE__
is used at the start of header files to prevent multiple definitions occurring.
When you use an expression like #define INT64 unsigned int the preprocessor does exactly the same thing. It evaluates the expression, then replaces all occurrences of INT64 with unsigned int.
When you use a typedef, on the other hand, the compiler makes the type substitution, which means the compiler can warn about incorrect use of your newly created type.
#define would simply warn you of an incorrect use of unsigned int which if you have a lot of type substitution can become confusing!
The following code:
#define MYDEF(x)
#define MYDEF(y)
int main() {}
gives me an error (or warning if pedantic-errors is disabled):
'MYDEF' macro redefined
The reason is different names for unused argument (more over, there is no body in macro). But why? In which situations it can be a problem?
Because macros are not functions. They are textual replacements done by the preprocessor and can't be overloaded.
It is (almost) similar to find and replace in your editor. Find all the occurences of MYDEF and replace it with (empty string in your case). It's more complicated, of course, but the idea is the same.
And you can't overload this find and replace, can you? :)
The macro can be redefined, and the macro is uniquely determined by the macro name. For example, code like this :
#define MYDEF(x) //the name of the macro is 'MYDEF'
#define MYDEF(x, y) //the name of the macro is 'MYDEF' too
MYDEF(x) will be redifined(or covered) by MYDEF(x, y), you can't write code MYDEF(x) any more after defining MYDEF(x, y)
so, if you write code :
#define MYDEF(x)
#define MYDEF(y) //(There compiler will give warning). You can write
//`#undef MYDEF` before `#define MYDEF(y)` to avoid it.
MYDEF(x) will be redifined by MYDEF(y).
I have a function in a header file:
template <int line>
inline void log() {}
And then I try this trick to make using it easier:
#define LOG_LINE log<__LINE__>()
And then in a .cpp file I do:
void main()
{
LOG_LINE;
}
And it seems that it works the way I'd like it to. I get the line from .cpp file, not the line at which LOG_LINE is declared in .h file. But I don't understand how it works. Does C++ perfrom double-pass preprocessing, leaving special macros like __LINE__ for second pass? Is this portable (standard) behavior? Should I expect this to work with all major C++ compilers? So far I've only tried MSVC.
One should distinguish between the number of passes through the entire input, which is what terms like single-pass normally refer to, and handling of nested expansions. The preprocessor normally expands all macros in a single pass through the file, but it correctly expands the expanded forms, until there is nothing left to expand.
That is, LOG_LINE gets expanded to log<__LINE__>(), where __LINE__ again gets expanded to 3, producing the final expansion log<3>() — all in a single pass through the compilation unit.
Yes, this is portable, standard behaviour. Yes you can depend on it.
The reason is that the #define command simply stores the tokens that constitute the expansion text without interpreting it or expanding it at all. Because they are tokens, white space and comments are not stored.
Then when the macro name is used in the program text, it is replaced by the expansion text (and any arguments as needed). Then any tokens in the substituted text are scanned and replaced, and so on (except there is no recursive replacement).
In your case it takes two expansions to get to the underlying line number.
See N3797 16.3. It's relatively readable, for a standards document. There are examples quite close to what you're asking.
This does not need double pass preprocessing. This is about the order of expansion of nested macros (well, in a sense, an expression is expanded in as many passes as needed to expand all the nested macros). A quote from an answer to this question:
All arguments which don't appear after the # operator or either side of a ## are fully macro expanded when they are replaced, not before the function-like macro is expanded.
I try to use code which is generating functions via a macro, which looks like this:
File A (Provided file I can't change anything here):
#define FUNCTION_GENERATOR(NUM) \
void MyGeneratedFunctionNo##NUM##(void) \
{ \
another_function_call(NUM); \
} \
FUNCTION_GENERATOR(1)
FUNCTION_GENERATOR(2)
FUNCTION_GENERATOR(3)
File B (My file where I wanna use function pointers to the generated functions from File A):
typedef void (*function_ptr) (void);
function_ptr func_array[3];
func_array[0] = MyGeneratedFunctionNo1;
func_array[1] = MyGeneratedFunctionNo2;
func_array[2] = MyGeneratedFunctionNo3;
...
Naturally the compiler complains that MyGeneratedFunctionNo1, MyGeneratedFunctionNo2, MyGeneratedFunctionNo3 are not defined.
Is there any way to use function pointers with this
generated functions?
The problem has nothing to do with function pointers per se. You will not be able to access these functions from other translation units in any way, pointers or not, because they are not declared in other translation units.
The typical macro based technique implies providing and using two macros: one for generating declarations and one for generating definitions
#define FUNCTION_GENERATOR_DECL(NUM) \
void MyGeneratedFunctionNo##NUM(void);
#define FUNCTION_GENERATOR_DEF(NUM) \
void MyGeneratedFunctionNo##NUM(void) \
{ \
another_function_call(NUM); \
}
After that you use the "definition" macro instantiations in some implementation file (as you already do)
FUNCTION_GENERATOR_DEF(1)
FUNCTION_GENERATOR_DEF(2)
FUNCTION_GENERATOR_DEF(3)
and you typically place the "declarator" macro instantiations into some header file.
FUNCTION_GENERATOR_DECL(1)
FUNCTION_GENERATOR_DECL(2)
FUNCTION_GENERATOR_DECL(3)
P.S. Also, note an important subtle point mentioned by #James Kanze in the comments (and which I missed initailly). The ## operator shall not be used to form invalid preprocessing tokens. In the preprocessor grammar ( is a separate independent preprocessing token (punctuator), while the function name is also a separate independent preprocessing token (identifier). If you attempt to forcefully concatenate the function name to the ( by using the ## operator, you'll end up with an invalid preprocessing token and undefined behavior.
Don't concatenate the ( to the function name. Remove the second ## from your macro definition. It will work as intended without it.
Just like any other function, you have to declare them. This is typically done in a header file.
You can do this directly, or you can define a macro similar to the one you have that defines the function.
Concretely, place this in a header file, which you include in both the file you define your functions in and in the file you use them:
extern void MyGeneratedFunctionNo1(void);
if in the beginning of my file i do
#define dbg_kprintf \
if (x_var) kprintf
I late on do statements using
dbg_kprintf ("blablabla");
My question is that will dbg_kprintf be only defined if xvar is defined somewhere else? If it is not then will dbg_kprintf statements not be used at compile time?
Thanks.
No, that will either compile into a run-time check of the variable, or nothing (if the variable is in fact compile-time constant with a false value and the optimizer feels like eliminating the dead code) or a call always (if it's a compile-time constant with a true value). So, now you know.
The typical way to ensure that debug code is excluded from non-debugging builds is to use a preprocessor symbol to guard the code. Note that it might require you to manage the arguments differently.
No, in that example, x_var has to exist somewhere or it will fail to compile. You are looking for something like
#if (x_var)
#define dbg_kprintf kprintf
#else
#define dbg_kprintf
#endif
In C/C++ Macros can take arguments. It will be defined either way, as it's just a pre-processing directive but the compile will fail if it's not defined. To pass an argument to a macro use this syntax
#define foo(X) ((X))
dbg_kprintf will be used before complie time. The preprocessor will substitute in its place the contents you defined: if (x_var) kprintf. Then it will try to compile your code normally.