0

I'm working with a microcontroller and want to write a macro that inserts a specific number of wait cycles. I want

DELAY_CYCLES(40)

to expand to

__asm(" RPT #40 || NOP");

Additional restrictions:

  1. Since this is a compiler-specific intrinsic it needs to match exactly. I can't rely on the compiler to merge strings. E.g. __asm(" RPT #""40"" || NOP"); is not correct.

  2. The manufacturer headers already define: #define NOP __asm(" NOP")

  3. I can't pass a string to the intrinsic. char str = " RPT #40 || NOP"; __asm(str); is not allowed.

At the moment I am not even sure if there is a solution to this special case.

6
  • 4
    Quick question: have you tried __asm(" RPT #""40"" || NOP");? __asm syntaxes in most compilers will process this just fine. Commented Dec 8, 2020 at 7:05
  • @nneonneo Actually no, I didn't think it will work. I will try it. Maybe the compiler is smarter than I assumed. Commented Dec 8, 2020 at 7:10
  • 1
    It’s not a matter of “smartness”. Strings are concatenated during preprocessing, before being parsed. If you’re going to do weird things with macros, you should start by learning how to use the preprocessor, including the different phases of translation. Commented Dec 8, 2020 at 7:14
  • 2
    @Sneftel err, pedantic correction, but it is the compiler which handles string merging. The preprocessor doesn't do it. (Check for yourself: echo 'char *x = "a""b";' | gcc -xc -E -; this prints char *x = "a""b";) Commented Dec 8, 2020 at 7:18
  • 1
    @nneonneo And it does affect string parsing. E.g. "\x1234" is an invalid escape sequence, but "\x12""34" compiles. Commented Dec 8, 2020 at 7:21

1 Answer 1

2

It's quite probable that your compiler will concatenate the string literals properly (despite point #1); GCC and Clang, for instance, will do this. In this case, the simple solution is the following macro:

#define DELAY_CYCLES(X) __asm(" RPT #" #X " || NOP");

But, on the rare occasion when you really need to create a single string, then you may consider some hackery like this:

#define A(X) __asm(#X)
#define B(X) A(X || NOP)
#define HASH #
#define DELAY_CYCLES(X) B(RPT HASH X)

DELAY_CYCLES(40) expands to __asm("RPT # 40 || NOP"), even with NOP defined as something else. The space between # and 40 cannot, to my knowledge, be elided with this technique unless you want to write DELAY_CYCLES(#40) or your preprocessor allows you to paste # and 40 together (GCC does not).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.