Reputation: 6112
The macro of interest (IOPORT_CREATE_PIN) is part of a library and works as desired in general. It converts a specific pin on a specific port to a library internal unique numeric representation.
It is defined as:
#define IOPORT_CREATE_PIN(port, pin) ((IOPORT_ ## port) * 8 + (pin))
Normal usage would be
IOPORT_CREATE_PIN(PORTD, 4)
for example, which would just concatenate IOPORT_ and PORTD to IOPORT_PORTD. IOPORT_PORTD in this example is an internal definition of the library that further expands to numeric value.
However, since PORTD (defined as #define PORTD (*(PORT_t *) 0x0660)
, which is not really relevant here) is already part of another definition
#define FLASHPORT PORTD
So using
IOPORT_CREATE_PIN(FLASHPORT, 4)
wrongly concatenates to IOPORT_FLASHPORT instead of the desired IOPORT_PORTD inside the IOPORT_CREATE_PIN definition.
I had a look at this interesting answer and tried to apply one level of indirection hoping the macro would be properly expanded, but I wasn't able to get it right.
Is there a way to "wrap" that macro somehow to make the compiler evaluate FLASHPORT to PORTD before the concatenation?
EDIT:
As John pointed out the problem with wrapping is, that FLASHPORT would be expanded recursively, not just from FLASHPORT to PORTD, but to (*(PORT_t *) 0x0660)
.
Is there any workaround?
Upvotes: 1
Views: 276
Reputation: 180978
Normally, the arguments to a function-like macro are themselves macro-expanded before being substituted into the macro's replacement text. Argument expansion is suppressed, however, for macro arguments that are operands of the concatenation (##
) or stringification (#
) operator -- that's the reason for performing a double-expansion if you want to concatenate or stringify a macro's replacement value instead of its name.
I can not change the IOPORT_CREATE_PIN macro. Is there a way to "wrap" that macro somehow to make the compiler evauate FLASHPORT to PORTD before the concatenation?
My understanding is that you want to define a new macro, e.g. WRAPPER()
that you can invoke instead of IOPORT_CREATE_PIN()
, whose expansion is the same as IOPORT_CREATE_PIN()
for arguments PORTD, 4
, and whose expansion does not change same when FLASHPORT
is used instead of PORTD
as the first argument.
Whether that is doable depends in part on the macro arguments. Generally, a straight-up wrapper does what I understand you to be asking for:
// For illustrative purposes:
#define IOPORT_PORTD correct!
#define IOPORT_FLASHPORT wrong!
// As specified in the question:
#define FLASHPORT PORTD
#define IOPORT_CREATE_PIN(port, pin) ((IOPORT_ ## port) * 8 + (pin))
// Wrapper:
#define WRAPPER(port,pin) IOPORT_CREATE_PIN(port, pin)
// Demo:
Direct call: IOPORT_CREATE_PIN(FLASHPORT, 4)
Wrapped call: WRAPPER(FLASHPORT, 4)
Wrapped call: WRAPPER(PORTD, 4)
The preprocessor exands that to:
Direct call: ((wrong!) * 8 + (4))
Wrapped call: ((correct!) * 8 + (4))
Wrapped call: ((correct!) * 8 + (4))
The catch here is that if PORTD
is defined as a macro in its own right, then you are hosed. You then cannot just expand FLASHPORT
to PORTD
; if FLASHPORT
is expanded then the result of that expansion will be expanded again, recursively, before it is substituted.
As far as I know or can determine, it is not possible to create a general-purpose alias for a preprocessor macro. Where no token-pasting or stringification is involved, you can do as you have done, and simply define one macro to expand to the name of another, but that doesn't play well with pasting or stringification.
If a for-purpose solution is acceptable, however, then there are alternatives. For example, if you can identify all the token-pasting operations that can involve your alias, then you can provide aliases for the pasted-together macros, too. In your case, that might look like this:
// For illustrative purposes:
#define IOPORT_PORTD correct!
#define PORTD OOPS
// As specified in the question:
#define FLASHPORT PORTD
#define IOPORT_CREATE_PIN(port, pin) ((IOPORT_ ## port) * 8 + (pin))
// Patch up the token-pasting:
#define IOPORT_FLASHPORT IOPORT_PORTD
// Demo:
Direct call: IOPORT_CREATE_PIN(FLASHPORT, 4)
The preprocessor expands that to
Direct call: ((correct!) * 8 + (4))
That doesn't scale well, of course, and it requires some knowledge or study of the overall macro set involved, but it would solve the limited-scope problem presented in the question.
Upvotes: 1
Reputation: 1374
Try this:
#define MY_IOPORT_CREATE_PIN(port, pin) IOPORT_CREATE_PIN(port ,pin)
and then use MY_IOPORT_CREATE_PIN instead of IOPORT_CREATE_PIN
Upvotes: 0