1

I want to create a global 22 character (+ NULL) string in C. I am initialising it like this:

#define SVN_REVISION     "1143"
#define SERIAL_NUMBER    "PST3201109270001"
char general_info[23] = SVN_REVISION SERIAL_NUMBER SAMPLING_FREQUENCY;

So far, this works fine. general_info is initialised with the concatenation of the two strings. Now, for the last two characters, I want them to be a 16-bit integer. But I can't simply do this:

#define SVN_REVISION          "1143"
#define SERIAL_NUMBER         "PST3201109270001"
#define SAMPLING_FREQUENCY    (UINT16)500
char general_info[23] = SVN_REVISION SERIAL_NUMBER SAMPLING_FREQUENCY SAMPLING_FREQUENCY;

What can I do?

Rocketmagnet
  • 5,656
  • 8
  • 36
  • 47

4 Answers4

1

You have to use the usual "stringify operator" trick.

#define STRINGIFY_HELPER(str) #str
#define STRINGIFY(str) STRINGIFY_HELPER(str)

#define SVN_REVISION          "1143"
#define SERIAL_NUMBER         "PST3201109270001"
#define SAMPLING_FREQUENCY    (UINT16)500
char general_info[23] = SVN_REVISION SERIAL_NUMBER SAMPLING_FREQUENCY STRINGIFY(SAMPLING_FREQUENCY);

You need the double macro to exploit the preprocessor # operator because the macro arguments are not expanded when the # operator is used. Thus, an extra macro step is needed to first expand the arguments, and then use the # operator. A good explanation can be found here.


edit

Actually, that won't work because of the (UINT16) cast, that will be stringified as well. You can still get away with macros only if you can afford creating an extra macro:

#define STRINGIFY_HELPER(str) #str
#define STRINGIFY(str) STRINGIFY_HELPER(str)

#define SVN_REVISION          "1143"
#define SERIAL_NUMBER         "PST3201109270001"
#define SAMPLING_FREQUENCY_NOCAST    500
#define SAMPLING_FREQUENCY    (UINT16)(SAMPLING_FREQUENCY_NOCAST)
char general_info[23] = SVN_REVISION SERIAL_NUMBER SAMPLING_FREQUENCY STRINGIFY(SAMPLING_FREQUENCY_NOCAST);

It isn't very elegant, but you still avoid the problem of duplicating the 500 value (you just have to update it in a single place and everything will work fine).

Community
  • 1
  • 1
Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
1

If you mean you want to embed 16-bit integer 500 as binary data in the end of the string, you can use raw hex bytes:

/* Little-endian unsigned 16-bit integer with the value 500 */
#define SAMPLING_FREQUENCY    "\xf4\x01"

Beware, though, endianness is architecture dependent, so you might want to add an extra macro to correctly order the bytes depending on the architecture:

#ifdef ... /* little endian */
#define BYTES2(a,b) b a
#else ... /* big endian */
#define BYTES2(a,b) a b
#endif
#define SAMPLING_FREQUENCY    BYTES16("x01", "\xf4")

EDIT: If you want to have a human-readable number, you can't have it at compile-time (at least not in C), but you can initialize it at runtime:

#define SVN_REVISION     "1143"
#define SERIAL_NUMBER    "PST3201109270001"
#pragma pack(push, 1)
union {
    struct {
        char svn_rev_serial[20];
        uint16_t freq;
        char nul;
    };
    char general_info[23];
} u = {{
    SVN_REVISION SERIAL_NUMBER,
    500,
    '\0'
}};
#pragma pack(pop)

This uses more non-standard (but well-supported) constructs, like #pragma pack and writing to one union member and reading from another.

Alex B
  • 82,554
  • 44
  • 203
  • 280
  • @themel, well, if it already dictates fixed-size binary data, *surely* it will not assume NULL-terminated strings... – Alex B Sep 28 '11 at 12:03
  • But now SAMPLING_FREQUENCY is not human readable, except in the comment. Is there some way to convert 500 into "\xf4\x01'" using the preprocessor? – Rocketmagnet Sep 28 '11 at 12:04
  • @Rocketmagnet not that I can think of at compile time. – Alex B Sep 28 '11 at 12:06
  • This is the best answer. However, I have decided to do it at run time, and use a union so that it makes more sense. – Rocketmagnet Sep 28 '11 at 12:19
0

Well, you can try this:

char general_info[23] = SVN_REVISION SERIAL_NUMBER SAMPLING_FREQUENCY;
strcat(genral_info, itoa(SAMPLING_FREQUENCY));
Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
0

Youy can try something like :

#define SVN_REVISION          "1143"
#define SERIAL_NUMBER         "PST3201109270001"
#define SAMPLING_FREQUENCY    "\xF4\x1\00\00"
char general_info[29] = SVN_REVISION SERIAL_NUMBER SAMPLING_FREQUENCY SAMPLING_FREQUENCY;

\xF4\x1\00\00 is the memory representation for decimal 500 (at least on Windows platforms)

Thierry Franzetti
  • 1,763
  • 12
  • 12