23

I have found a piece of code that defines register access permissions for a chip. Using arm-none-eabi-gcc it compiles correctly.

Here is the code:

static const uint8_t defaultRegisterAccess[REGISTER_COUNT] =
{
//  0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F
    0x03, 0x23, 0x01, 0x02, 0x02, 0x01, 0x01, 0x03, ____, ____, ____, ____, ____, ____, ____, ____, // 0x00 - 0x0F
    0x02, 0x02, 0x01, 0x02, 0x02, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, // 0x10 - 0x1F
    ____, ____, 0x02, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, // 0x20 - 0x2F
    ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, // 0x30 - 0x3F
    0x02, 0x01, 0x02, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, // 0x40 - 0x4F
    ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, // 0x50 - 0x5F
    ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, 0x01, 0x01, 0x03, ____, ____, 0x01, // 0x60 - 0x6F
    0x03, 0x01, 0x01, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____  // 0x70 - 0x7F
};

I find it elegant and a readable way to define registers, but how does the compiler interpret ____? I don't see any definitions for it.

My first guess would be that it is an elision; if no one uses the value then it is not seen by the compiler? Or am I missing something?

8
  • 9
    Have you tried adding this to your code? #pragma message "The value of ____ is: " VALUE(____) Commented Nov 2 at 21:26
  • A somewhat related question: stackoverflow.com/q/1642028/1483676 Commented Nov 3 at 13:37
  • Another example: QMK uses _______ (seven underscores), an alias of the (pseudo) keycode KC_TRANSPARENT. Commented Nov 4 at 3:35
  • For bitmaps, you can use a define for numeric transform to ascii art. It is a good way to display fonts and other information in source. You can use some visually identical glyph with a different encoding and be standards compliant. This whole point seems like FUD. Double underscore is so that library writers can say, the name space collision is your fault. Commented Nov 6 at 14:11
  • "I don't see any defines for it" - you probably could have found the define if you added -E or -imacros or some other related flag to your compile options. Commented Nov 8 at 23:07

1 Answer 1

35

____ does not have any particular meaning. It is just an identifier that is defined as a macro earlier in the source file or in an include file. Among other matches, I found this source file on Github by searching for static const uint8_t defaultRegisterAccess. The macro expands to 0x00, but using it makes the array more readable: actual registers stand out with their access bits while non registers appear as blanks.

Fragments from the file tmc2208_api.h:

// [...]

#define ____  0x00

// [...]

// Register access permissions:
//   0x00: none (reserved)
//   0x01: read
//   0x02: write
//   0x03: read/write
//   0x23: read/write, flag register (write to clear)
static const uint8_t defaultRegisterAccess[REGISTER_COUNT] =
{
//  0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F
    0x03, 0x23, 0x01, 0x02, 0x02, 0x01, 0x01, 0x03, ____, ____, ____, ____, ____, ____, ____, ____, // 0x00 - 0x0F
    0x02, 0x02, 0x01, 0x02, 0x02, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, // 0x10 - 0x1F
    ____, ____, 0x02, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, // 0x20 - 0x2F
    ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, // 0x30 - 0x3F
    0x02, 0x01, 0x02, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, // 0x40 - 0x4F
    ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, // 0x50 - 0x5F
    ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, 0x01, 0x01, 0x03, ____, ____, 0x01, // 0x60 - 0x6F
    0x03, 0x01, 0x01, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____  // 0x70 - 0x7F
};

If your file does not have the definition, it may have been moved to a header file.

Also note that, as commented by @pmg, the C Standard (C23 6.4.3.1 §7) specifies that All identifiers that begin with a double underscore [...] are reserved for any use and all identifiers that begin with an underscore are reserved for use as identifiers with file scope in both the ordinary and tag name spaces, so this practice, while elegant and common, invokes undefined behavior albeit unlikely to cause problems.

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

23 Comments

Reminder (C23 6.4.2.1.7) All identifiers that begin with a double underscore [...] are reserved for any use
A potential alternative: _00_
Or just use three spaces and 0.
that is a good reminder... But this is a beautiful macro that makes that table extremely easy to read.
a beautiful macro that makes that table extremely easy to read I don't agree. What does ____ mean? It's literally been obfuscated and matches none of the supposedly-allowed values in the comments in the source. So now you have to look somewhere else.
The main problem is that for C23, there's no clear draft corresponding with the final ISO document. Part of the reason why is because ISO are so dreadfully inefficient at publishing documents, so that by the time they finally got around to publish C23, the ISO C working group were already quite far into the next C2Y standard. In order to fund the extreme amount of bureaucracy and 2 years of stalling that the ISO organization is adding to the project, they need money. Summary: ISO/IEC is actively striving to be the enemy of all technology and innovation.
I am willing to bet that the amount of money collected from actual sales of this ISO Standard in pdf format is vanishingly small compared to the cost of this bureaucracy. Seems like time to switch to ECMA :)
I don't think ISO C makes any difference between identifiers in terms of variables/functions and identifiers in terms of macro names. The syntax for the latter being # define identifier. And macros are visible everywhere within the translation unit until the translation phase that executes them is completed, or indeed until #undef. But there's no #undef here, so...
When the system provides a header, is it part of the implementation? If you write a header and use names starting with double underscores (etc), then you're treading on thin ice. Don't do it! However, if the header is provided for you — as I assume tmc2208_api.h is provided by the system — then it could be legitimate for it to use ____ because it is part of the implementation. It is dangerous to look at system headers for guidelines on how to write user-defined headers. They operate under different (implementation) rules from the (non-implementation) headers that you write.
The fact that the Standard would allow an implementation to define a function named stranger, which measures the anger of a string, and would allow the implementation to behave in arbitrary fashion if user code were to attempt to define a function with that name, does not imply that there's a realistic likelihood of any implementation designer who wasn't being deliberately obtuse doing so.
@Lundin "Summary: ISO/IEC is actively striving to be the enemy of all technology and innovation." -- Ouch. I won't argue with that. "...bureaucracy and 2 years of stalling...." So far I refuse to call C23 by "C24" just because it took them so long to put ink to paper that they finally had to put "C24" on the tin.
t's just an "off-by-one" error! :-) Besides, C17 wasn't published until 2018 either. I still refer to the languages as C17 and C23 even though the standards were not published until the following year. (Some prominent members of the C committee appear to refer to versions of the language using those names too.) When quoting from the standard (which defines the language, but is a separate entity), I should probably reference it in full as ISO/IEC 9899:2024 or whatever, but I'm too lazy to do that.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.