Shouldn't this:
#define MOGSH_CONCAT (x,y) x##y
#define MOGSH_DOUBLE (a,b) MOGSH_CONCAT(a,b)
#define MOGSH_DEFINEPROC (p) MOGSH_DOUBLE(_gt,p) options_dialog::p;
MOGSH_DEFINEPROC(AssignMainForm);
happily expand to:
_gtAssignMainForm options_dialog::AssignMainForm;
Given that _gt is not defined, _gtAssignMainForm is:
typedef void (__stdcall *_gtAssignMainForm)();
and options_dialog is just a class where AssignMainForm is a static member.
Instead, in MSVC9, I get the error:
'a' : undeclared identifier
on the line containing
MOGSH_DEFINEPROC(AssignMainForm);
In the definition of a function-like macro there can be no whitespace between the macro name and the ( beginning the parameter list.
#define MOGSH_CONCAT(x,y) x##y
// ^ no whitespace allowed here
As you have it now (with whitespace), MOGSH_CONCAT is an object-like macro with a replacement list of (x,y) x##y, which is why you are getting such strange results.
Related
Im working on a big project and I have a lot of errno macros.
I want to write a helper functions for the logger that stringify each of these errno to a string. i decided to use x-macros but Im getting compilation errors
in the first place the code was like this:
// project_errno.h
#define PROJECT_ERR_KEY_FAILURE 12222
#define PROJECT_ERR_CIPHER_ZERO_PADDING 12345
#define PROJECT_ERR_FAILED_TO_SETUP_ENC_KEY 14004
the way i sort it out is as the following:
In a different file i places the x-macros:
// project_errno.hx
PROJECT_ERR_FUNC(PROJECT_ERR_KEY_FAILURE) 12222
PROJECT_ERR_FUNC(PROJECT_ERR_CIPHER_ZERO_PADDING) 12345
PROJECT_ERR_FUNC(PROJECT_ERR_FAILED_TO_SETUP_ENC_KEY) 14004
then I turned it into an enum:
// project_errno.h
enum {
#define PROJECT_ERR_FUNC(name, value) name=value,
#include "project_errno.hx"
#undef PROJECT_ERR_FUNC
};
then i added a function that will be used by the logger:
// logging.h (declaration) and (definition) logging.c
const char* stringify_errno(int errno) {
switch (errno) {
#define PROJECT_ERR_FUNC(name, value) case name: return #value ;
#include "project_errno.hx"
#undef PROJECT_ERR_FUNC
}
}
So, looks pretty good, but i can't get it to compile, Im getting the following compilation errros:
project_errno.h:8:53: error: error: expected identifier before numeric constant
#define PROJECT_ERR_CIPHER_ZERO_PADDING 12345
^
..../project_errno.h:17:30: note: in definition of macro ‘PROJECT_ERR_FUNC’
#define PROJECT_ERR_FUNC(name, value) name=value,
^~~~
..../project_errno.hx:47:14: note: in expansion of macro ‘PROJECT_ERR_CIPHER_ZERO_PADDING ’PROJECT_ERR_FUNC(PROJECT_ERR_CIPHER_ZERO_PADDING, 12345)
project_errno.h:8:53: error: error: expected ‘}’ before numeric constant
#define PROJECT_ERR_CIPHER_ZERO_PADDING 12345
^
..../project_errno.h:17:30: note: in definition of macro ‘PROJECT_ERR_FUNC’
#define PROJECT_ERR_FUNC(name, value) name=value,
^~~~
..../project_errno.hx:47:14: note: in expansion of macro ‘PROJECT_ERR_CIPHER_ZERO_PADDING ’PROJECT_ERR_FUNC(PROJECT_ERR_CIPHER_ZERO_PADDING, 12345)
project_errno.h:8:53: error: expected unqualified-id before numeric constant
#define PROJECT_ERR_CIPHER_ZERO_PADDING 12345
^
..../project_errno.h:17:30: note: in definition of macro ‘PROJECT_ERR_FUNC’
#define PROJECT_ERR_FUNC(name, value) name=value,
^~~~
..../project_errno.hx:47:14: note: in expansion of macro ‘PROJECT_ERR_CIPHER_ZERO_PADDING ’PROJECT_ERR_FUNC(PROJECT_ERR_CIPHER_ZERO_PADDING, 12345)
^~~~~~~~~~~~~~~~~~~~~~~
In file included from ......../project_errno.h:20:1: error: expected declaration before ‘}’ token
};
^
..../project_errno.h:17:30: note: in definition of macro ‘PROJECT_ERR_FUNC’
#define PROJECT_ERR_FUNC(name, value) name=value,
^~~~
..../project_errno.hx:47:14: note: in expansion of macro ‘PROJECT_ERR_CIPHER_ZERO_PADDING ’PROJECT_ERR_FUNC(PROJECT_ERR_CIPHER_ZERO_PADDING, 12345)
^~~~~~~~~~~~~~~~~~~~~~~
I can't understand why im getting those errors (im getting the same error message multiple time in the same compilation session), and i hope you guys could help me.
Also, if you have any other solution to solve the problem i intended to solve in the first place (using the errno macros and add a functions to stringify those errnos whenever Im adding an errno to the project [in only one place]), i'd love to hear about it Thanks
I'd follow the recipe shown in the Wikipedia page about X Macros:
Implementation
An X macro application consists of two parts:
The definition of the list's elements.
Expansion(s) of the list to generate fragments of declarations or statements.
The list is defined by a macro or header file (named, LIST) which generates no code by itself, but merely consists of a sequence of invocations of a macro (classically named X) with the elements' data. Each expansion of LIST is preceded by a definition of X with the syntax for a list element. The invocation of LIST expands X for each element in the list.
In particular the second example, the one with X macro as argument
Pass name of the worker macro into the list macro. This both avoids defining an obscurely named macro (X), and alleviates the need to undefine it.
Which, in OP's use case, leads to the following three files:
// project_errno.h
#ifndef PROJECT_ERRNO_H
#define PROJECT_ERRNO_H
#define FOR_EACH_ERR_ID_VALUE_PAIR(DO) \
DO(PROJECT_ERR_KEY_FAILURE, 12222) \
DO(PROJECT_ERR_CIPHER_ZERO_PADDING, 12345) \
DO(PROJECT_ERR_FAILED_TO_SETUP_ENC_KEY, 14004)
#define DEFINE_ENUM_ITEM(err, value) err = value,
enum project_errs {
FOR_EACH_ERR_ID_VALUE_PAIR( DEFINE_ENUM_ITEM )
};
#undef DEFINE_ENUM_ITEM
#endif
// logging.h
#ifndef LOGGING_H
#define LOGGING_H
const char* stringify_errno(int errno);
#endif
// logging.c
#include <stdio.h>
#include "project_errno.h"
#define STRINGIFY_ERR_VALUE_NAME(name, value) case name: \
return "[" #value "] " #name;
const char* stringify_errno(int errno)
{
switch (errno) {
FOR_EACH_ERR_ID_VALUE_PAIR(STRINGIFY_ERR_VALUE_NAME)
default:
return "[-----] UNKWOWN";
}
}
#undef STRINGIFY_ERR_VALUE_NAME
Testable here: https://wandbox.org/permlink/aNJCI7lQihkFnYzp
Edited answer:
I was able to generate the enum using
enum {
#define PROJECT_ERR_FUNC(name) , name =
PROJECT_ERR_START_OF_ENUM = -1
#include "project_errno.hx"
#undef PROJECT_ERR_FUNC
};
but had to remove the backtick at the end of project_errno.hx. The above code will only work if you do not include project_errno.h before.
A complete minimum working program would be
enum {
#define PROJECT_ERR_FUNC(name) , name =
PROJECT_ERR_START_OF_ENUM = -1
#include "project_errno.hx"
#undef PROJECT_ERR_FUNC
};
#include <iostream>
int main() {
std::cout << PROJECT_ERR_KEY_FAILURE << std::endl;
return 0;
}
that will print 12222.
There is a macro that I want to use that takes arguments in this format:
COMB(unique identifier, argument 1, argument 2, argument 3)
I want to create a wrapper for it that automatically generates the unique identifier. I found this answer that has code to generate a random ID, which I am using in my code:
#define PP_CAT(a, b) PP_CAT_I(a, b)
#define PP_CAT_I(a, b) PP_CAT_II(~, a ## b)
#define PP_CAT_II(p, res) res
#define UNIQUE_NAME(base) PP_CAT(base, __COUNTER__)
#define COMB_U(key, ...) COMB(UNIQUE_NAME(comb_r_), key, __VA_ARGS__)
// Using the macro
// The parameters are enums
COMB_U(KB_1, KB_2, KC_Y)
When I compile this I get a bunch of errors from inside of the COMB macro code like this:
‘cmb_UNIQUE_NAME’ declared as function returning an array
function ‘cmb_UNIQUE_NAME’ is initialized like a variable
As well as inside of the file with my code:
‘comb_r_’ undeclared here (not in a function)
#define COMB_U(key, ...) COMB(UNIQUE_NAME(comb_r_), key, VA_ARGS)
And a bunch of messages that don't seem to be associated with an error, like this one:
note: in expansion of macro ‘COMB_U’
COMB_U(KB_1, KB_2, KC_Y)
How can I fix this?
For reference, the source for the COMB macro is here: https://github.com/germ/qmk_firmware/blob/master/keyboards/gboards/g/keymap_combo.h
I have a problem with macros. I am supposed to come up with a macro ENTRY, that puts a value into an array ( scanf("%d",&ENTRY(x,i)) was given).
I tried: #define ENTRY (a,b) (a[b-1]), but that didn't work.
It created a compiler error that says, that a and b are undeclared.
But I thought that I don't have to declare variables used in macros, especially because, for example: #define min(a,b) ((a)<(b)?(a):(b)) worked in another program.
So what am I doing wrong here?
#include <stdio.h>
#define N 3
#define ENTRY (a,b) (a[b-1])
int main(void)
{
int x[N],i;
float y[N];
for(i=1;i<=N;i++){ printf("x_%d = ",i);scanf("%d",&ENTRY(x,i));}
for(i=1;i<=N;i++){ printf("y_%d = ",i);scanf("%lf",&ENTRY(y,i));}
return 0
}
Function-like macro definitions can't have whitespace after the macro name
#define ENTRY (a,b) (a[b-1]) // wrong
=>
#define ENTRY(a,b) ((a)[(b)-1]) // correct
6.10 – Preprocessing directives:
...
control-line:
...
# define identifier lparen identifier-listopt ) replacement-list new-line
# define identifier lparen ... ) replacement-list new-line
# define identifier lparen identifier-list , ... ) replacement-list new-line
...
lparen:
a ( character not immediately preceded by white-space
With the space, you get an object-like macro that expands to (a,b) (a[b-1]).
(For additional robustness, it's also recommended to parenthesize the parameters so that it also works if you pass in more complex expressions.)
I'm not sure if that's the right terminology to use, however my problem is that the a macro call ("PLUGIN_NAME") as a parameter to another macro call ("IMPLEMENT_MODULE"), which in turn prints it as a string, prints that argument as the macro call ("somePLUGIN_NAME") rather than the expanded result ("someSomePluginName").
Note that "IMPLEMENT_MODULE" is an API call so I can't change that.
#define IMPLEMENT_MODULE(name) something##name
#define PLUGIN_NAME SomePluginName
#define _STR(s) #s
#define STR(s) _STR(s)
#define PLUGIN_NAME_STR STR(PLUGIN_NAME)
int main()
{
string expected = "somethingSomePluginName";
string actual = STR(IMPLEMENT_MODULE(PLUGIN_NAME));
printf("expected: %s || actual: %s\n", expected.c_str(), actual.c_str());
assert(expected == actual);
}
I've put it here:
http://codepad.org/FRzChJtD
You need another helper macro to concatenate the preprocessor tokens after macro-expanding them:
#define IMPLEMENT_MODULE_2(A, B) A##B
#define IMPLEMENT_MODULE(name) IMPLEMENT_MODULE_2(something, name)
See working example here
This technical explanation is that macro expansion will not occur if the token-pasting (##) or stringizing operator (#) are found by the preprocessor.
I want to repeatedly instantiate a class, within module scope, without providing a unique name. Something like this.
MyClass name##__LINE__(); // doesn't work because __LINE__ won't stringify
MyClass name##__LINE__(); // duplicate identifier error - two name__LINE__ variables
Is there some way to do this, either creating a unique name or using some anonymous context, such as an initializer or struct?
See this answer
#define CONCATENATE_DETAIL(x, y) x##y
#define CONCATENATE(x, y) CONCATENATE_DETAIL(x, y)
#define MAKE_UNIQUE(x) CONCATENATE(x, __LINE__)
MyClass MAKE_UNIQUE(name);
MyClass MAKE_UNIQUE(name);
...
Or just make an array:
MyClass arr[N];
Why these macros work
C11 standard, 6.10.3.1 Argument substitution:
After the arguments for the invocation of a function-like macro have been identified,
argument substitution takes place. A parameter in the replacement list, unless preceded
by a # or ## preprocessing token or followed by a ## preprocessing token (see below), is
replaced by the corresponding argument after all macros contained therein have been
expanded. Before being substituted, each argument’s preprocessing tokens are
completely macro replaced as if they formed the rest of the preprocessing file; no other
preprocessing tokens are available.
Corresponding paragraph in C++ standard (16.3.1 Argument substitution) is exact copy of C standard's.
You need to double nest the concatenation operator
struct A{};
#define JOIN(X, Y) JOIN_DETAIL(X, Y)
#define JOIN_DETAIL(X, Y) JOIN_DETAIL2(X, Y)
#define JOIN_DETAIL2(X, Y) X##Y
int main() {
A JOIN(a, __LINE__);
A JOIN(a, __LINE__);
}