1

I'm looking for a way to have a fixed length Device name in C++ at compile-time, as string literal.

For example :

#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)

#define VERSION 6
#define DEVICE_NAME "MyDevice" STR(VERSION)

A fixed length with leading zeros to fit 4 digits is my desired output, Just like as "MyDevice0006", The actual output using previous code is "MyDevice6".

I've searched and found this answer :

#undef VER
#define VER ...your version number...

#undef SMARTVER_HELPER_
#undef RESVER
#if VER < 10
#define SMARTVER_HELPER_(x) 000 ## x
#elif VER < 100
#define SMARTVER_HELPER_(x) 00 ## x
#elif VER < 1000
#define SMARTVER_HELPER_(x) 0 ## x
#else
#define SMARTVER_HELPER_(x) x
#endif
#define RESVER(x) SMARTVER_HELPER_(x)

But Trying it gives me the error :

error: expected ‘;’ before numeric constant
#define SMARTVER_HELPER_(x) 00 ## x
                            ^

Is there an enhanced code to do this ?

Hamza Hajeir
  • 119
  • 1
  • 8
  • 2
    `in C++` So why tag C? C is not C++. `at compile-time (Preprocessing)` And in C++ there may be no need to use preprocessing. You want to have that done _specifically_ with preprocessor __or__ in C++ at compile-time? – KamilCuk Nov 23 '20 at 11:43
  • LibFmt might be able to do this, I know it has some constexpr support, not sure if it can handle this case – JVApen Nov 23 '20 at 11:43
  • 4
    Can you describe what kind of functionality you need? Depending of that detail it is possible (or not) to solve your problem using `constexpr`, which is more clear then using macros. – Marek R Nov 23 '20 at 11:46
  • 1
    C++ has lots of compile time capabilities. Valid use cases or macros are extremely rare nowadays. Please pick one language. If using the preprocessor is a strict requirement then it doesn't matter that much, but thats a weird requirement – 463035818_is_not_an_ai Nov 23 '20 at 11:46
  • I think this error can be solved by `#define SMARTVER_HELPER_(x) ## 00 ## x`. but this is not a good solution as others said – علی سالمی Nov 23 '20 at 11:48
  • You really need to specify which language the question is about, and if you are looking for a compile-time generated _string literal_ or just compile-time generated code. – Lundin Nov 23 '20 at 12:44
  • @KamilCuk, I know the difference between C/C++, but the desired output is highly applicable to both related languages. I need it to be at compile-time. I've changed the question to not hold 'preprocessing' anymore. – Hamza Hajeir Nov 23 '20 at 19:22
  • @JVApen By a quick eye, Its binary seems to be added to the binary I have, It's not desired as I'm working with embedded devices. – Hamza Hajeir Nov 23 '20 at 19:26
  • @MarekR I need to number my devices at production as unique friendly sequenced names (not chip-id or MAC-Address). These names are used to communicate with each device separately. – Hamza Hajeir Nov 23 '20 at 19:28
  • @علیسالمی Unfortunately it doesn't work. – Hamza Hajeir Nov 23 '20 at 19:32

1 Answers1

4

Very ugly but this should do the trick:

#include <stdio.h>

#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)

#define VERSION 6

#if (version < 10)
    #define DEVICE_NAME "MyDevice000" STR(VERSION)
#elif (version < 100)
    #define DEVICE_NAME "MyDevice00" STR(VERSION)
#elif (version < 1000)
    #define DEVICE_NAME "MyDevice0" STR(VERSION)
#else
    #define DEVICE_NAME "MyDevice" STR(VERSION)
#endif

int main(void)
{
    puts(DEVICE_NAME);
}
David Ranieri
  • 39,972
  • 7
  • 52
  • 94
  • that could be generalized with some ternary operators, even like `#define DEVICE_NAME ( version<10 ? "MyDevice000"STR(VERSION) : version<100 ? "MyDevice00" STR(VERSION) : etc.`. I could see even like `#define PAD_ZEROS(str) ( sizeof(str) < 3 ? "00"str : sizeof(str) < 4 ? "0"STR : etc.` – KamilCuk Nov 23 '20 at 11:47
  • @KamilCuk Thanks for pointing that out, but can you please show how? AFAIK you can not use `sizeof` with the preprocessor: https://stackoverflow.com/a/4079267/1606345, or you mean at runtime?, it seems that OP wants this to work at compile time. – David Ranieri Nov 23 '20 at 11:53
  • 1
    Yes, that would be evaluated at runtime, still optimized by compiler. https://godbolt.org/z/cbGTxh it depends on the use case anyway. – KamilCuk Nov 23 '20 at 12:02
  • Thanks, It worked well. Just edit the `version` to match the defined one. You consider it ugly, What would you think the 'neat' way would use ? – Hamza Hajeir Nov 23 '20 at 19:38
  • @HamzaHajeir It depends, if you are on c++, as pointed out by others, I will use `const_expr`, if you need a C/C++ solution, there are not many alternatives :( – David Ranieri Nov 23 '20 at 19:42
  • It's C++, I've no good knowledge about `constexpr`. Can you share a good starting reference ? – Hamza Hajeir Nov 23 '20 at 19:58
  • I'm not sure about how to return a string from a `const_expr`, let me ask my minions tomorrow, stay tuned ... – David Ranieri Nov 23 '20 at 21:08
  • 1
    @HamzaHajeir does this helps? https://godbolt.org/z/PqWzrh – David Ranieri Nov 24 '20 at 11:35
  • Thanks , It worked well, but other compilers (as cpp.sh) gives this error `12:1: error: body of constexpr function 'constexpr auto get_version()' not a return-statement`. It's the same of what my compiler gives. – Hamza Hajeir Nov 24 '20 at 12:36
  • It requires c++14 or more ... it seems that you are compiling with c++11 – David Ranieri Nov 24 '20 at 12:48
  • Under c++11 you can use https://godbolt.org/z/TT7GWE but notice that get_version() here is not solved at compile time (but at runtime) – David Ranieri Nov 24 '20 at 12:52
  • I see, It's ok if it's solved at the very beginning of the run-time. – Hamza Hajeir Nov 24 '20 at 12:53
  • Oh, in such case you can use https://godbolt.org/z/PnfEzY and avoid the `static` var – David Ranieri Nov 24 '20 at 13:01
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/225071/discussion-between-david-ranieri-and-hamza-hajeir). – David Ranieri Nov 25 '20 at 05:39