3

I am trying to use ## preprocessor operator to determine witch GPIO to use. here is my code :

#define GPIO_Pin_1 0x0001
#define GPIO_Pin_2 0x00CA
#define GPIO_Pin_3 0x00DE
#define GPIO_Pin_4 0x00AC

#define DIVIDE(a , b) ( (a) / (b) )
#define NUMBER_TO_GPIO(a) GPIO_Pin_##DIVIDE(a , 2)

int gpioNumber = 8;
int gpioAddress = NUMBER_TO_GPIO(gpioNumber);

desired value of gpioAddress is 0x00AC (GPIO_Pin_4 ) but compiler gives this error: "GPIO_Pin_DIVIDE declared implicitly" . i want to concat GPIO_Pin_ and result of DIVIDE(a,b) macro

  • 1
    "i want to concat GPIO_Pin_ and result of DIVIDE(a,b) macro" What do you expect as result of `DIVIDE` macro? Do you expect a numerical value?` – Gerhardh Feb 12 '18 at 15:26
  • i expect result of NUMBER_TO_GPIO(gpioNumber) gives GPIO_Pin_4 – Metin kundakçıoğlu Feb 12 '18 at 15:29
  • if NUMBER_TO_GPIO(2) result GPIO_Pin_1 , if NUMBER_TO_GPIO(3) result GPIO_Pin_1 , if NUMBER_TO_GPIO(3) result GPIO_Pin_2 , if NUMBER_TO_GPIO(4) result GPIO_Pin_2 , if NUMBER_TO_GPIO(8) result GPIO_Pin_4 – Metin kundakçıoğlu Feb 12 '18 at 15:31
  • 2
    C preprocessor does text replacement. Not mathematical evaluation. The result would be `((gpioNumber) / (2))` which is not really suitable for any concatenation attempts. – Gerhardh Feb 12 '18 at 15:31
  • is that any way to do mathematical evaluation on preprocessor ? only text replacement is not enough for my problem – Metin kundakçıoğlu Feb 12 '18 at 15:34
  • 2
    Why don't you use a function? – Matthias Feb 12 '18 at 15:37
  • These values are constant values and never changes. i need fastest operations. If i use functions , that adds extra operations to runtime. – Metin kundakçıoğlu Feb 12 '18 at 15:40
  • The C preprocessor does textual substitution. It evaluates conditions (look up [C11 §6.4.7 Preprocessing numbers](https://port70.net/~nsz/c/c11/n1570.html#6.4.7) if you want to be horrified) but the text replacement is done as text replacement. If you feel the 'need for speed' (watch Top Gun rather than the more recent movie by that name), use an array that maps the numbers as you need. – Jonathan Leffler Feb 12 '18 at 15:42
  • use constexpr, which is highly probable to not add any overhead. – The Techel Feb 12 '18 at 15:46
  • @TheTechel — 'probable' --> 'portable' if you're quick. – Jonathan Leffler Feb 12 '18 at 15:46
  • @ArnavBorborah: That duplicate isn't really driving to the heart of the problem here. It's related; it isn't a duplicate. – Jonathan Leffler Feb 12 '18 at 15:47
  • @JonathanLeffler Ok, I thought it was really similar, so I considered closing as a duplicate. – Arnav Borborah Feb 12 '18 at 15:48
  • 2
    Could you please decide which language you are using? You added both C and C++ but you can only use one at a time. – Gerhardh Feb 12 '18 at 15:48
  • Note that `gpioNumber` is a variable, not even a constant. There's no way to map that to 4 at compile time. The preprocessor doesn't even know what it is. – Jonathan Leffler Feb 12 '18 at 15:48
  • @JonathanLeffler i added gpioNumber variable to explain my problem. in original code is something like this : initPin( NUMBER_TO_GPIO(8)) ; initPin function accepts NUMBER_TO_GPIO(8) as input. – Metin kundakçıoğlu Feb 12 '18 at 15:56
  • Why do you need to write `8` and not just write `4` directly? Indeed, if you can write `8` or `4`, why not just write `GPIO_Pin_4`? What are the extra issues that make writing `8` desirable? – Jonathan Leffler Feb 12 '18 at 15:58
  • @Gerhardh this library will use in c and c++ platforms. different projects different platforms. – Metin kundakçıoğlu Feb 12 '18 at 16:00
  • 1
    Whenever you come up with complex macros for something so simple such as setting a gpio pin, you know that your program design has gone haywire. Most likely this is a XY problem and you should not use macros to solve it in the first place. For example, this smells like a plain look-up table would be handy. – Lundin Feb 12 '18 at 16:05
  • @Jonathan Leffler this macro is symbolic to explain my problem. original code part : #define MOD(a) ( (a)%16 ) #define DIVIDE(a) ( (a) / 16 ) #define NUMBER_TO_GPIO(a) GPIO_Pin_##DIVIDE(a) #define NUMBER_TO_PORT(a) GPIO##MODE(a) int gpio = 8; int port = NUMBER_TO_PORT(gpio); int pin = NUMBER_TO_PIN(gpio); this will be a library and users can modify gpio number before compile. after compilation this values will not change. – Metin kundakçıoğlu Feb 12 '18 at 16:07
  • If you set a single global variable once, the function call overhead is an irrelevancy (it'll be minuscule anyway, but calling it once is a no-brainer). Otherwise, you get them to define the value you need, or you write out conditional code in the preprocessor to evaluate it using a sequence of `#if` / `…` / `#elif` / `…` / `#else` / `#error You didn't set GPIO_PIN_NUMBER sensibly` / `#endif` or some such paragraph. The preprocessor does textual substitution — it only does calculations in conditions. Live with it — it isn't likely to change. – Jonathan Leffler Feb 12 '18 at 16:14

4 Answers4

1

As mentioned in the comments, your macros won't work. You could use an array:

const int GPIO_Pins[] = {
    /*GPIO_Pin_1*/ 0x0001,
    /*GPIO_Pin_2*/ 0x00CA,
    /*GPIO_Pin_3*/ 0x00DE,
    /*GPIO_Pin_4*/ 0x00AC
};
#define NUMBER_TO_GPIO(a) GPIO_Pins[(a) / 2 - 1]

Of course the problem is no bounds checking.

001
  • 13,291
  • 5
  • 35
  • 66
1

In case of C++, use constexpr to compute the value at compile time.

static constexpr std::array<int, 4> Pins = { 0x01, 0x0A, 0xDE, 0xAC };

static constexpr int pin2(int a)
{
    return Pins[a / 2];
}
The Techel
  • 918
  • 8
  • 13
1

There is no good way to do what you're trying to do with just the CPP. Especially since you are calculating GPIO number at runtime.

The only way to make sure that it's a direct substitution at compile-time is to use the indexes directly (which you're not doing)

Consider this as a solution in C:

const long GPIO_PINS[] = { 0xFFFF, 0x0001, 0x00CA, 0x00DE, 0x00AC };
static inline long getGPIOAddr(int gpioAddress) {
    return GPIO_PINS[gpioAddress >> 1];
}

int main() {
    const int gpioNumber = 8;
    return getGPIOAddr(gpioNumber);
}

Here is the assembly output of gcc (clang gives something similar):

gcc -S -O foo.c

    .file   "foo.c"
    .text
    .globl  main
    .type   main, @function
main:
.LFB1:
    .cfi_startproc
    movl    $172, %eax ; NOTICE THE OPTIMIZATION HERE!
    ret
    .cfi_endproc
.LFE1:
    .size   main, .-main
    .globl  GPIO_PINS
    .section    .rodata
    .align 32
    .type   GPIO_PINS, @object
    .size   GPIO_PINS, 40
GPIO_PINS:
    .quad   65535
    .quad   1
    .quad   202
    .quad   222
    .quad   172
    .ident  "GCC: (GNU) 7.2.0"
    .section    .note.GNU-stack,"",@progbits

For completeness here is clang:

    .file   "foo.c"
    .text
    .globl  main
    .align  16, 0x90
    .type   main,@function
main:                                   # @main
    .cfi_startproc
# BB#0:
    movl    $172, %eax
    ret
.Ltmp0:
    .size   main, .Ltmp0-main
    .cfi_endproc

    .type   GPIO_PINS,@object       # @GPIO_PINS
    .section    .rodata,"a",@progbits
    .globl  GPIO_PINS
    .align  16
GPIO_PINS:
    .quad   65535                   # 0xffff
    .quad   1                       # 0x1
    .quad   202                     # 0xca
    .quad   222                     # 0xde
    .quad   172                     # 0xac
    .size   GPIO_PINS, 40


    .ident  "clang version 3.4.2 (tags/RELEASE_34/dot2-final)"
    .section    ".note.GNU-stack","",@progbits

any good modern compiler can determine that gpioNumber does not change during a particular AST and will substitute the constant properly.

So stop trying to outsmart the compiler, it is MUCH better at optimizations than you are.

If you are interested in how far back the compilers are good at this, I've loaded this code at godbolt here:

https://godbolt.org/g/EWjsHB

You can look at disassembly of the code at your heart's content. all compilers there optimize this stuff out with a -O as the option.

Ahmed Masud
  • 21,655
  • 3
  • 33
  • 58
0

## concats the symbols. Hence, you form a symbol GPIO_Pin_DIVIDE that is unknown.

What you could do is:

#define GPIO_Pin_1 0x0001
#define GPIO_Pin_2 0x00CA
#define GPIO_Pin_3 0x00DE
#define GPIO_Pin_4 0x00AC

#define DIVIDE(a , b) ( (a) / (b) )
#define NUMBER_TO_GPIO(a) (DIVIDE( GPIO_Pin_##a , 2))

int gpioAddress = NUMBER_TO_GPIO(4);

but I'm not sure whether this is what you mean.

Matthias
  • 8,018
  • 2
  • 27
  • 53
  • While that preprocesses, the output is `int gpioAddress = (( (0x00AC) / (2) ));` whereas for the macro invocation with 8, the desired output was `int gpioAddress = 0x00AC;`. You no longer need the DIVIDE because you've changed that 8 into 4 manually (in the source code). So, with the altered parameter, `#define NUMBER_TO_GPIO(a) GPIO_Pin_ ## a` would suffice. – Jonathan Leffler Feb 12 '18 at 15:53
  • You are right. I thought the objective is to correct the address, but it aims for the index. – Matthias Feb 12 '18 at 15:55
  • thanks for answer but this is not what i want. i will not divide the address. address are constant. i am trying to decide witch address i will use to init GPIO – Metin kundakçıoğlu Feb 12 '18 at 16:10