5

In one of my projects I'm defining the current version as a decimal value, which looks something like that:

#define MINOR_VERSION 13

In order to be able to output the version when asked for it, I need to get the hex representation into a string. Currently I'm working with sprintf(), which basically looks like this:

char buffer[3];
sprintf(buffer, "%2x", MINOR_VERSION);
// output buffer

This has a couple of drawbacks, one of which is the increased code size as sprintf() needs to be included. Furthermore the value gets calculated during runtime, which is wasted effort anyway. Both of these issues are critical to me, as I'm working with microcontrollers here.

Maybe I'm missing the totally obvious, but I can't come up with a nice and clean macro doing the conversion for me. In principle I need a way to convert 13 into its hex representation (2 digits, without the typically preceding 0x) 0d during compilation.

What would you suggest?

Karol Babioch
  • 666
  • 8
  • 16

5 Answers5

3

Flip the problem around, and define the version as a hexadecimal. When you need to use it as a string, use the answer from here to convert it to a string. Then you can do things like this:

#include <stdio.h>

#define VERSION 0xd
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)

int main() {
  printf("hello " TOSTRING(VERSION) "\n");
  printf("%d\n", VERSION);
}
Community
  • 1
  • 1
razeh
  • 2,725
  • 1
  • 20
  • 27
  • This probably works, but its not quite as convenient as I initially wanted it to be, because you have to "think" in hex when changing the version number :(. Thanks anway! – Karol Babioch Dec 30 '13 at 13:33
1

I'm assuming you'll be incrementing MINOR_VERSION manually. If this is so, why go through the trouble of having a macro convert this to a string for you. Simply have this number in both binary and string form in a definition:

#define MINOR_VERSION_BIN (13)
#define MINOR_VERSION_STR ("D")

I understand that you may find this risky, for example, you may increment one but not the other, however, the preprocessor is very limited in what it can do. It is better suited for substitution, not conversion.

Fiddling Bits
  • 8,712
  • 3
  • 28
  • 46
  • It is good to approach the problem from a different point of view, but I've found that if I repeat something like a version string, eventually I mess it up, and change one but not the other. – razeh Dec 30 '13 at 01:11
  • Well, that is certainly a possibility, however I don't like it very much, because it forces me to update two values for a version bump. Furthermore you could always argue that these two values will diverge over time, because someone is going to forget and/or overlook it. – Karol Babioch Dec 30 '13 at 01:11
1

You could create the string manually:

#define HEX_DIGIT(digit) "0123456789ABCDEF"[(digit)]
#define MAKE_HEX(value) HEX_DIGIT((value) < 16? (value): ((value)/16)%16), \
                        HEX_DIGIT((value) < 16? 16: (value)%16),           \
                        0

#define MINOR_VERSION_BIN 13
char const version[] = { MAKE_HEX(MINOR_VERSION_BIN) };
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
1

Trust the compiler. If you absolutely insist on having it resolved at compile time, use constant expressions.

char MINOR_VERSION_STR[3] { 
    '0'+(MINOR_VERSION >>4)&0xF,
    '0'+(MINOR_VERSION)&0xF, 
    0 };

That'll work up to minor version 63 -- though admittedly with a leading zero. I submit that if you get past 64 minor versions it's time for another major release. Or you can expand this upward through addition nybbles if you really want to

If the leading 0 bothers you, you could use a conditional expression -- which, again, an optimizer ought to be able to resolve at compile time --

char MINOR_VERSION_STR[3] { 
    MINOR>VERSION > 15 ? '0'+(MINOR_VERSION >>4)&0xF : '0'+(MINOR_VERSION)&0xF,
    MINOR>VERSION > 15 ? '0'+(MINOR_VERSION)&0xF : 0, 
    0 };

No macro required, though of course you could turn this into one if you think you'll be using it in other places.

Alternatively, rather than using sprintf, write a small dedicated function for the purpose. As demonstrated her that can be pretty darned tiny and pretty darned fast.

Think of C as high-level assembler. The libraries are great, but when the library doesn't meet your needs, tweak the bits yourself.

keshlam
  • 7,931
  • 2
  • 19
  • 33
0

Define you master MINOR_VERSION textually as a string in the desire (hexadecimal) format.
Let the int version of MINOR_VERSION derive from that.

#define MINOR_VERSION_S " D"
#define MINOR_VERSION strtol(MINOR_VERSION_S, 0, 16)

Note: The result of OP's sprintf(buffer, "%2x", MINOR_VERSION); is " D".

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256