sierrafoxtrot / srecord

SRecord github Mirror
https://srecord.sourceforge.net/
GNU General Public License v3.0
46 stars 23 forks source link

[Format request]: C++ array #63

Open jaskij opened 1 year ago

jaskij commented 1 year ago

Call me crazy, but I program microcontrollers in C++.

To that end, while the C array is perfectly adequate, over the years the languages are diverging more and more. I propose adding a new output format, the C++ array.

The question is of specific output format, how it should be done.

My idea is to:

To that end, I believe the outline below to be appropriate. Although I would love for someone with a better grasp of the C++ standard to check if what I'm doing here with inline vs static is the right way.

#ifndef FOO_H
#define FOO_H

#ifndef SREC_CAT_QUALIFIER
    #ifdef __cpp_inline_variables
        #define SREC_CAT_QUALIFIER inline
    #else
        #define SREC_CAT_QUALIFIER static
    #endif
#endif

SREC_CAT_QUALIFIER constexpr std::array<uint8_t, LENGTH_HERE> foo = {
    // data goes here, the same as in the C array
};

SREC_CAT_QUALIFIER constexpr size_t foo_termination = 0x00;
SREC_CAT_QUALIFIER constexpr size_t foo_start       = 0x00;
SREC_CAT_QUALIFIER constexpr size_t foo_finish      = 0x00;

#endif // FOO_H

More on the inline keyword: cppreference.com notes:

Because the meaning of the keyword inline for functions came to mean "multiple definitions are permitted" rather than "inlining is preferred", that meaning was extended to variables.

If my understanding is correct, inline will result in more of a guarantee that the array will not be duplicated in the resulting program/library.

jaskij commented 1 year ago

This came about because, while GCC will do what it always does, constexpr in theory gives more avenues for optimization than a simple const, especially if said const is extern.

jaskij commented 1 year ago

To add: just now, the lack of constexpr has prevented me from using static_assert to make sure correct compile-time options were selected.

Edit: which was solved by including the generated .c file, but that always feels... bad.

sierrafoxtrot commented 1 year ago

Hi @jaskij, you certainly aren't alone in writing firmware in C++. I've been involved in doing just that on-and-off for the past 20+ years. This is a great idea!

Regarding C++ standards, I'd be keen to keep it to features from C++14 or earlier. This will give the best chance of aligning with a validated compiler for heavily regulated industries such as medical device development and safety systems. Implementing the actual format itself will be pretty straight forward (I've already done the boilerplate :-) )

As for the question around inline vs static vs [other option], I've reached out to a couple of friends and will give it some thought. Others who contribute to SRecord may also want to offer advice.

Meanwhile, regarding:

Edit: which was solved by including the generated .c file, but that always feels... bad. Using the −INClude option will generate a .h intended to be included. If I've understood your dilemma, this may alleviate your conscience.

jaskij commented 1 year ago

Regarding C++ standards, I'd be keen to keep it to features from C++14 or earlier.

From my knowledge, the only interesting point is inline, which was introduced in C++17. And which was #ifdefed in my proposal because of it. Hopefully I got the feature macro correctly.

Using the −INClude option will generate a .h intended to be included. If I've understood your dilemma, this may alleviate your conscience.

No, the C header doesn't work, because extern const cannot be used in a constexpr expression. And while I know that in practice static const is the same, I still prefer getting the constexpr. C++ is a bit too big to be able to accurately predict compiler behavior.

I work in a small company, with a lot of freedom, so I luckily have the option to use basically whatever ARM's latest release of GNU Toolchain supports (C++20, at the moment).

jaskij commented 7 months ago

I got reminded of this issue recently, and just today learned about C23's #embed. Reading further ( https://thephd.dev/finally-embed-in-c23 ), it should probably make it into C++26.