Discussion:
How to get an integer constant into a string literal as character?
(too old to reply)
Philipp Klaus Krause
2016-12-01 16:59:05 UTC
Permalink
Raw Message
How can I put an integer constant into a string literal as a character?
I'm looking for a somewhat elegant macro M such that

#define I 255
const char *test = "test" M(I) "test";

after preprocessing ends up as

const char *test = "test" "\xff" "test";

(or the same string literal represented differently).

Philipp
Philipp Klaus Krause
2016-12-01 17:18:41 UTC
Permalink
Raw Message
Sorry for the noise. This should have gone to comp.lang.c instead.

Philipp
s***@casperkitty.com
2016-12-01 18:09:44 UTC
Permalink
Raw Message
Post by Philipp Klaus Krause
How can I put an integer constant into a string literal as a character?
I'm looking for a somewhat elegant macro M such that
#define I 255
const char *test = "test" M(I) "test";
after preprocessing ends up as
const char *test = "test" "\xff" "test";
No such feature exists. IMHO, the Standard should provide a means of
creating a variably-sized statically-allocated data structure which
combines string literals and other data, but no such means presently
exists.
Kaz Kylheku
2016-12-01 20:46:18 UTC
Permalink
Raw Message
Post by Philipp Klaus Krause
How can I put an integer constant into a string literal as a character?
I'm looking for a somewhat elegant macro M such that
#define I 255
const char *test = "test" M(I) "test";
after preprocessing ends up as
const char *test = "test" "\xff" "test";
(or the same string literal represented differently).
There isn't any way to do decimal to hex conversion in
the preprocessor. Character constants may use only hex
or octal escapes.

All I can think of at the moment is that your best bet is
to use octal.

#define I 377 /* must be 1 to 3 digits wide
#define STR(S) #S
#define M(OCT) STR(\OCT)

"abc" M(I) "xyz" /* expands t "abc" "\377 "xyz" */

The following would be better, but there is a problem:

#define I FF
#define STR(S) #S

#define M(HEX) STR(\x ## HEX)

The \x ## HEX operation produces an invalid token, which is
undefined behavior. It might work in many compilers, but
due to no requirement coming from ISO C.

There isn't any way to take material from a macro argument
such as HEX, and glue it with some preceding material without
an intervening space, other than the token pasting operator ##
which must produce a valid token.

The option of producing "\x" "FF" also doesn't exist; a character escape
in a string literal cannot be split across multiple literals
in this manner. What we have here is a string literal with
a bad \x syntax, followed by the string literal "FF" giving two
F characters.

If I had to solve this problem, I would avoid it entirely.

#define I "\xFF"

Then just use "test" I "test".

If these #defines are a primary objects, then just bite the bullet
and duplicate material as necessary: make separate macros which
give 255 as a numeric or character constant, and as a string
literal.

If the #define I is generated, tweak the generator to output
the information in the right form, and any additional forms.

There are ways to structure such parallel information.

Below, we write a macro which takes a pseudo-parameter P,
from which it calculates three different constants.

The caller passes in the expression I, which is itself not
defined as a macro, but which is used as a partial key for
retrieving three different macros.

$ gcc -E -x c -
#define I_STR "\xFF"
#define I_CHR '\xFF'
#define I_DEC 255

#define MX(PARAM, TYPE) PARAM ## _ ## TYPE
#define M(PARAM, TYPE) MX(PARAM, TYPE)

#define FUNNY_MACRO(P) do { \
int x = M(P, DEC); \
char c = M(P, CHR); \
char *s = "test" M(P, STR) "test" \
} while (0);

FUNNY_MACRO(I)

[Ctrl-D][Enter]
# 1 "<stdin>"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "<stdin>"
# 14 "<stdin>"
do { int x = 255; char c = '\xFF'; char *s = "test" "\xFF" "test" } while (0);
Jakob Bohm
2016-12-02 02:39:58 UTC
Permalink
Raw Message
Post by Philipp Klaus Krause
How can I put an integer constant into a string literal as a character?
I'm looking for a somewhat elegant macro M such that
#define I 255
const char *test = "test" M(I) "test";
after preprocessing ends up as
const char *test = "test" "\xff" "test";
(or the same string literal represented differently).
Philipp
I guess the closest thing (though it may be a vendor extension) is:

const static char test[] = { "test", I, "test", 0 };

The idea is that the compiler allows a string constant to stand in for
a sequence of individual characters in an array initializer for an
array of char.

The following two are of cause in the standard:

const static char test[] = "test\x55test";
const static char test[] = { 't', 'e', 's', 't', I, 't', 'e', 's',
't', 0 };

But I am unsure about the following convenient variants:

const static char test[] = { "test\x55test", 0 };
const static char test[] = { "test", I, "test", 0 };


Enjoy

Jakob
--
Jakob Bohm, CIO, Partner, WiseMo A/S. https://www.wisemo.com
Transformervej 29, 2860 Søborg, Denmark. Direct +45 31 13 16 10
This public discussion message is non-binding and may contain errors.
WiseMo - Remote Service Management for PCs, Phones and Embedded
Loading...