Macro to manipulate chars inside string

A

Andre

Hi all,

I need a macro to transform an value like 274A into {(char)0x27, (char)
0x4A}. Does anyone know how to do it, or where can I find more
information about this kind of macro?

Thanks,

Andre
 
B

Ben Pfaff

Richard Heathfield said:
Andre said:
I need a macro to transform an value like 274A into {(char)0x27, (char)
0x4A}. Does anyone know how to do it, or where can I find more
information about this kind of macro?

It's not absolutely to me clear what you want to do, but I /think/ you
want to load 0x274A into the first two members of an array of
char. This is somewhat muddied by C's allowing chars to be wider than
8 bits, but if we just assume you want the high 8 bits in the first
char, and the low 8 bits in the second, you can do this:

#define U16_TO_CHAR2(arr, x) \
do { (arr)[0] = ((x) & 0xFF00) >> 8; \
(arr)[1] = (x) & 0xFF; } \
while(0)

To do this, I'd write a function, e.g. following your model:

#include <stdint.h>

void u16_to_char2(unsigned char arr[2], unsigned int x)
{
arr[0] = (x & 0xff00) >> 8;
arr[1] = x & 0xff;
}
 
A

Andre

I wasn't clear enough.

The value I have will be in the following format 75B22636-668E-11CF-
A6D900AA0062CE6C, and I would like to transform it into {(char)0x75,
(char)0xB2, (char)0x26, (char)0x36, (char)0x66, ... , (char)0x6C}.

Thanks,

Andre
 
B

Ben Pfaff

Andre said:
I wasn't clear enough.

The value I have will be in the following format 75B22636-668E-11CF-
A6D900AA0062CE6C, and I would like to transform it into {(char)0x75,
(char)0xB2, (char)0x26, (char)0x36, (char)0x66, ... , (char)0x6C}.

Do you get this value at runtime or compile time?
 
K

Keith Thompson

Andre said:
Compile time

75B22636-668E-11CF-A6D900AA0062CE6C is not a valid piece of C code.

Do you have a string literal in your program? How did it get there?
 
J

jacob navia

Andre a écrit :
I wasn't clear enough.

The value I have will be in the following format 75B22636-668E-11CF-
A6D900AA0062CE6C, and I would like to transform it into {(char)0x75,
(char)0xB2, (char)0x26, (char)0x36, (char)0x66, ... , (char)0x6C}.

Thanks,

Andre

You are trying to transform a string uuid into an uuid:

Use:

Under windows:

#include <rpc.h>
RPC_STATUS RPC_ENTRY UuidFromString(
unsigned char __RPC_FAR *StringUuid,
UUID __RPC_FAR *Uuid
);

Under linux:
#include <uuid/uuid.h>

int uuid_parse( char *in, uuid_t uu);

DESCRIPTION
The uuid_parse function converts the UUID string given by in into the binary representation. The
input UUID is a string of the form 1b4e28ba-2fa1-11d2-883f-b9a761bde3fb (in printf(3) format
"%08x-%04x-%04x-%04x-%012x", 36 bytes plus the trailing '\0').

jacob
 
S

Seebs

I wasn't clear enough.

The value I have will be in the following format 75B22636-668E-11CF-
A6D900AA0062CE6C, and I would like to transform it into {(char)0x75,
(char)0xB2, (char)0x26, (char)0x36, (char)0x66, ... , (char)0x6C}.

This is still pretty unclear.

Do you want a literal translation at compile time, where you'll have a
compile-time string 75B2..., and you want to transform it into a
compile-time string { (char) ...}?

Or do you have incoming data at runtime, and you want to translate it into
a series of values in an array?

-s
 
P

Peter Nilsson

Andre said:
I wasn't clear enough.

The value I have will be in the following format 75B22636-
668E-11CF-A6D900AA0062CE6C, and I would like to transform
it into {(char)0x75, (char)0xB2, (char)0x26, (char)0x36,
(char)0x66, ... , (char)0x6C}.

How does it get from the original source into your C source?
Can you supply 75B22636,668E,11CF,A6D900AA0062CE6C instead?
Then you can use a variant of Richard's method (if you have
a compiler that supports unsigned long long.)

#include <stdio.h>

#define UUID(p0, p1, p2, p3) \
{ UUID_X4(p0), UUID_X2(p1), UUID_X2(p2), UUID_X8(p3) }

#define UUID_X8(p1) UUID_8(0x ## p1 ## ull)
#define UUID_X4(p1) UUID_4(0x ## p1 ## ul )
#define UUID_X2(p1) UUID_2(0x ## p1 ## u )

#define UUID_8(x) UUID_4((x) >> 32), UUID_4(x)
#define UUID_4(x) UUID_2((x) >> 16), UUID_2(x)
#define UUID_2(x) UUID_1((x) >> 8), UUID_1(x)
#define UUID_1(x) ((x) & 0xFF)

#define countof(x) ((size_t) (sizeof (x) / sizeof *(x)))

int main(void)
{
size_t i;
unsigned char uuid[] = UUID(75B22636,668E,11CF,A6D900AA0062CE6C);

for (i = 0; i < countof (uuid); i++)
printf(" %02X", 0u + uuid);
putchar('\n');

return 0;
}
 
A

Andre

Hi all,

I apologize for my confusing questions.

I have something like the following in my code

#define ASF_OBJECT_GUID_HEADER "75B22630668E11CFA6D900AA0062CE6C"

And if variable test is created in the following

char test[] = ASF_OBJECT_GUID_HEADER;

its values would be

test[0] = '7'
test[1] = '5'
test[2] = 'B'
test[2] = '2'
....
test[32] = '6'
test[31] = 'C'
test[32] = 0

And I would like to know if that is a way to create a macro to
redefine ASF_OBJECT_GUID_HEADER

#define ASF_OBJECT_GUID_HEADER SOME_COOL_MACRO_HERE
(75B22630668E11CFA6D900AA0062CE6C)

Now, it test is create in the same way as before

char test[] = ASF_OBJECT_GUID_HEADER;

Its values would be

test[0] = '75'
test[1] = 'B2'
....
test[15] = '6C'
test[16] = 0

Thanks,

Andre
 
K

Keith Thompson

Andre said:
I apologize for my confusing questions.

I have something like the following in my code

#define ASF_OBJECT_GUID_HEADER "75B22630668E11CFA6D900AA0062CE6C"

So there are no '-' characters, unlike everything you've told us so
far.

Wait, you have "something like" that? How much like it? Can you tell
us what you actually have rather than what it resembles?

How did that string literal get into your code? How much control do
you have over it? Can you write it as "\x75\xB2...\x6C"?

[...]
And I would like to know if that is a way to create a macro to
redefine ASF_OBJECT_GUID_HEADER

#define ASF_OBJECT_GUID_HEADER SOME_COOL_MACRO_HERE
(75B22630668E11CFA6D900AA0062CE6C)

And now it's no longer a string literal. Again, what *exactly* are
you starting with, and how much control do you have over it?

A macro can apply operations (such as <<, &, et al) to an operand to
generate a value at run time, or even at compile time if the

Now, it test is create in the same way as before

char test[] = ASF_OBJECT_GUID_HEADER;

Its values would be

test[0] = '75'
test[1] = 'B2'
...
test[15] = '6C'
test[16] = 0

I seriously doubt that. '75' is a multi-character constant; its value
is implementation-defined. I guess you mean '\x75'.

Is there any reason you can't just write

{ '\x75', '\xB2', ... }

in the first place?
 
E

Eric Sosman

Hi all,

I apologize for my confusing questions.

I have something like the following in my code

#define ASF_OBJECT_GUID_HEADER "75B22630668E11CFA6D900AA0062CE6C"

And if variable test is created in the following

char test[] = ASF_OBJECT_GUID_HEADER;

its values would be

test[0] = '7'
test[1] = '5'
test[2] = 'B'
test[2] = '2'
...
test[32] = '6'
test[31] = 'C'
test[32] = 0

And I would like to know if that is a way to create a macro to
redefine ASF_OBJECT_GUID_HEADER

#define ASF_OBJECT_GUID_HEADER SOME_COOL_MACRO_HERE
(75B22630668E11CFA6D900AA0062CE6C)

Now, it test is create in the same way as before

char test[] = ASF_OBJECT_GUID_HEADER;

Its values would be

test[0] = '75'

You probably don't mean that. I'll guess that you
mean `\x75' instead.
test[1] = 'B2'
...
test[15] = '6C'
test[16] = 0

If you absolutely must do this, I guess you might
proceed more or less like this:

#define HEX(c) ('0' <= (c) && (c) <= '9' ? (c)-'0' \
: (c) == 'A' ? 10 : (c) == 'B' ? 11 \
: (c) == 'C' ? 12 : (c) == 'D' ? 13 \
: (c) == 'E' ? 14 : 15 )
#define PAIR(u,v) (HEX(u) << 4 | HEX(v))
#define SOME_COOL_MACRO_HERE(x) { \
PAIR((x)[0],(x)[1]), PAIR((x)[2],(x)[3]), \
PAIR((x)[4],(x)[5]), PAIR((x)[6],(x)[7]), \
...
PAIR((x)[30],(x)[31]), 0 }

This approach has many disadvantages. There's no way to check
that the right number of characters has been supplied, nor that
they are all valid hex digits. Also, it's not suitable for
initializing a static variable because the array subscripts
(that is, the pointer dereferences) -- mean that the expressions
inside the initializer are not "constant expressions").

I find I'm unable to rid myself of the strong feeling that
you are doing something stupi^H^H^H^H^Hyou will regret.
 
T

Thad Smith

Andre said:
I need a macro to transform an value like 274A into {(char)0x27, (char)
0x4A}. Does anyone know how to do it, or where can I find more
information about this kind of macro?

I don't think you can do it with the Standard C preprocessor. It's time to
write a little utility to do the transformation.
 
E

Ersek, Laszlo

I don't think you can do it with the Standard C preprocessor. It's time to
write a little utility to do the transformation.

Like

$ printf '%s\n' '75B22636-668E-11CF-A6D900AA0062CE6C' \
| sed 's/-//g;s/\(..\)/0x\1u, /g'

returns

0x75u, 0xB2u, 0x26u, 0x36u, 0x66u, 0x8Eu, 0x11u, 0xCFu, 0xA6u, 0xD9u,
0x00u, 0xAAu, 0x00u, 0x62u, 0xCEu, 0x6Cu,

(Line break added manually for readibility.) The input string must have
an even number of nibbles.

----v----
static const char unsigned uuid[] = { UUID_INITIALIZER_LIST };
----^----

$ gcc -c -D UUID_INITIALIZER_LIST="$(printf ... | sed ...)" source.c

With bash, one can use the <<< redirection operator ("here string")
instead of the printf command and the pipeline.

$ sed 's/-//g;s/\(..\)/0x\1u, /g' <<< '75B22636-668E-11CF-A6D900AA0062CE6C'

Note that C90 6.5.7 "Initialization" explicitly allows the trailing
comma (also shown in Example 5), and so does C99 6.7.8 "Initialization".
The C99 Rationale v5.10 says in 6.7.8 "Initialization", page 89, lines
5-9:

----v----
K&R allows a trailing comma in an initializer at the end of an
initializer-list. The Standard has retained this syntax, since it
provides flexibility in adding or deleting members from an initializer
list, and simplifies machine generation of such lists.
----^----

Cheers,
lacos
 
B

bartc

Thad Smith said:
I don't think you can do it with the Standard C preprocessor. It's time
to write a little utility to do the transformation.

#include "stdio.h"

#define themacro(x) {(char)(x>>8),(char)(x&255)}

int main(void) {
char a[2]=themacro(0x274A);

printf ("A = %X %X\n",a[0],a[1]);
}

Or am I missing something?

(The value is expanded into decimal rather than hex constants; that didn't
seem important as you don't usually see the macro expansions)
 
K

Keith Thompson

bartc said:
Thad Smith said:
I don't think you can do it with the Standard C preprocessor. It's time
to write a little utility to do the transformation.

#include "stdio.h"

#define themacro(x) {(char)(x>>8),(char)(x&255)}

int main(void) {
char a[2]=themacro(0x274A);

printf ("A = %X %X\n",a[0],a[1]);
}

Or am I missing something?

(The value is expanded into decimal rather than hex constants; that
didn't seem important as you don't usually see the macro expansions)

No, the macro expanded into constant expressions such as
``(char)(0x274A>>8)'' and ``(char)(0x274A&255)''. The results of
evaluating those constant expressions are numeric values which are
not inherently either decimal or hexadecimal.

Note that converting a value exceeding 127 to char might cause
problems. It's almost certainly better to use unsigned char.

As far as I can tell, we *still* don't know exactly what the original
poster is asking for.
 
A

Andrew Poelstra

As far as I can tell, we *still* don't know exactly what the original
poster is asking for.

He went away after somebody (Jacob Navia, I think) suggested he
use his system's UUID en/decoding functions, and the example
values he gave looked an awful lot like UUID's, so I'd say
that was a safe bet that's what he needed.

(Specifically, I think he wanted to copy UUID's from his system
into a #define in some include file and have the code interpret
it properly without needing any special formatting.)

Andrew
 
M

Michael Tsang

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
I need a macro to transform an value like 274A into {(char)0x27, (char)
0x4A}. Does anyone know how to do it, or where can I find more
information about this kind of macro?

Don't use macros. They are dangerous. Use inline functions instead.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEARECAAYFAktrzCwACgkQm4klUUKw07ClwwCdHm+RyWuiDPcH+6Xp/Rs+bhNB
dn8AniI/07Z9gcywUG/LKEejzS+lfeEA
=X+DB
-----END PGP SIGNATURE-----
 
E

Eric Sosman

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


Don't use macros. They are dangerous. Use inline functions instead.

When you've figured out a way to make an inline function
return a brace-enclosed list of values, please tell us how
you did it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top