1

I have a C header file that has a list of definitions like below

#define TAG_A   ((A*)0x123456)
#define TAG_B   ((B*)0x456789)

I include that file in a cpp file.
I want to cast those definition in a switch case like below

unsigned int get_tag_address(unsigned int i)
{
    switch(i)
    {
        case reinterpret_cast<unsigned int>(TAG_A):
        return 1;
        case reinterpret_cast<unsigned int>(TAG_B):
        return 2;
    }
    return 3;
}

I still get compiler error that I can't cast a pointer to an unsigned intigeter.

What do I do wrong?

The definitions look at hardware addresses of an embedded system. I want to return an unsigned integer based on what hardware component is used (i.e. passed into the function argument). This is how I ended up in that situation.

PS: The header file containing the defitions must not change.

MrBit
  • 290
  • 4
  • 20

1 Answers1

1

It is impossible to use TAG_A and TAG_B in a case of a switch, except by using preprocessor tricks like stringifying the macro replacement itself in a macro and then parsing the value form the resulting string, which will however make the construct dependent on the exact form of the TAG_X macros and I feel is not really worth it when you don't have a strict requirement to obtain compile-time constant values representing the pointers.

The results of the expressions produced by the TAG_A and TAG_B replacement can not be used in a case operand because the operand must be a constant expression, but casting an integer to a pointer as done with (A*) and (B*) disqualifies an expression from being a constant expression.

So, you will need to use if/else if instead:

unsigned int get_tag_address(unsigned int i)
{
    if(i == reinterpret_cast<unsigned int>(TAG_A)) {
        return 1;
    } else if(i == reinterpret_cast<unsigned int>(TAG_B)) {
        return 2;
    } else {
        return 3;
    }
}

Also, consider using std::uintptr_t instead of unsigned int for i and in the reinterpret_casts, since it is not guaranteed that unsigned int is large enough to hold the pointer values. However, compilation of the reinterpret_cast should fail if unsigned int is in fact too small. (It is possible that std::uintptr_t in <cstdint> does not exist, in which case you are either using pre-C++11 or, if not that, it would be a hint that the architecture does not allow for representing pointers as integer values. It is not guaranteed that this is possible, but you would need to be working some pretty exotic architecture for it to not be possible.)

And if you can, simply pass, store and compare pointers (maybe as void*) instead of integer values representing the pointers. That is safer for multiple reasons and always guaranteed to work.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • "It is fundamentally impossible to use TAG_A and TAG_B in a case of a switch" This is not quite true. Stringize it, extract the number, convert to integer. All is doable with the preprocessor and constexpr functions. You should know the format of the `#define` but this is not a show-stopper. – n. m. could be an AI Aug 01 '22 at 18:10
  • @n.1.8e9-where's-my-sharem. Yes true, I really meant the expression resulting from the `TAG_X` replacement. I doubt that the macro tricks are worth it here though. I modified the answer accordingly. – user17732522 Aug 01 '22 at 18:53