Page 1 of 1

Switch embedded in enum definition?

Posted: Sat Nov 14, 2020 12:42 pm
by Schol-R-LEA
I was experimenting with the Raspberry Pi bare bones code, to see what I could learn from it, and ran across an odd bit of code in the C source. In the definition of the enum containing the MMIO, GPIO, and UART constants, the first entry, meant to define the MMIO base address, is:

Code: Select all

    // The MMIO area base address.
    switch (raspi) {
        case 2:
        case 3:  MMIO_BASE = 0x3F000000; break; // for raspi2 & 3
        case 4:  MMIO_BASE = 0xFE000000; break; // for raspi4
        default: MMIO_BASE = 0x20000000; break; // for raspi1, raspi zero etc.
    }
Now, I will admit that I tried to compile this blind, as part of what I wanted to see was how easy the tutorial was to follow. Not surprisingly, GCC did not recognize this idiom as a legitimate way to define an enum constant. While the intent seems clear, it isn't legal C code, as far as I can tell.

I simply replaced it with the appropriate sub-entry (the case 3 entry), but the code as given caught my interest.

However, I am curious as to why this was in the code sample. Is there an actual way to do this using a switch() statement (as opposed to, say, #define and #ifdef directives)?

Is this in the code primarily as a 'copy trap' (by which I mean, it is there to force the programmers following the tutorial to actually read the code), or is there a real idiom which this is meant to apply?

As an aside, AFAICT the triplet for AArch64 has changed to 'aarch64-none-elf-' rather than just 'aarch64-elf-', presumably to improve the consistency with other triplets. I don't want to change this in the wiki page until I have confirmed this, however.

Re: Switch embedded in enum definition?

Posted: Sat Nov 14, 2020 1:32 pm
by sj95126
It sure doesn't seem like that's legal. An enum can be a constant expression, which itself can be a conditional expression, but switch is neither of those.

You *could* do the same thing with a nested series of ternary operators, which are conditional expressions, but that would get pretty messy.

I know this makes me a grouch, but it's kind of annoying when coders use a feature to the extreme just because they can. I'm rarely impressed by "look how clever I am!"

Re: Switch embedded in enum definition?

Posted: Sat Nov 14, 2020 1:43 pm
by xenos
I'm not that familiar with C. In C++, I would probably use something similar by putting the switch in a constexpr function:

Code: Select all

int constexpr rpi = 4;

unsigned int constexpr baseaddr(int raspi)
{
	switch (raspi)
	{
	case 2:
	case 3: return 0x3F000000; // for raspi2 & 3
	case 4: return 0xFE000000; // for raspi4
	default: return 0x20000000; // for raspi1, raspi zero etc.
	}
}

enum mmio : unsigned int
{
	MMIO_BASE = baseaddr(rpi)
};

Re: Switch embedded in enum definition?

Posted: Sun Nov 15, 2020 5:25 pm
by moonchild
I would use a macro with a ternary if. Something like this:

Code: Select all

#define RASPI_BASEADDR(ver) (((ver == 2) || (ver == 3)) ? 0x3F000000 : \        
                             (ver == 4)                 ? 0xFE000000 : \
                             0x20000000)
#define RASPI_VER 3

enum {
        BASEADDR = RASPI_BASEADDR(RASPI_VER),
};

Re: Switch embedded in enum definition?

Posted: Mon Nov 16, 2020 1:50 am
by Kazinsal
That has to be a copy trap. It's such a blindingly absurd way of doing compile-time constants with a conditional base address that I can't imagine it being anything else.