How to convert binary to hex using a macro?

C

Chen Shu

Hi there:
These days I came to a problem that I failed to convert a binary
number to a hex number using a macro. For example:

int a = BINARY4(0101) will become int a = 0x5;
int a = BINARY8(0001,0101) will become int a = 0x15;
...etc.

I've written the following macros:

#define HEX_0000 0
#define HEX_0101 5
... ...
#define HEX_(a) HEX_ ## a
#define COMBINE(a) (0x ## a)
#define BINARY(a) COMBINE(HEX_(a))

These macros work all right in VC7, but when I compile the program
using VC8 or GCC-3.4.4, the result is wrong. When using GCC, the result
is:

int a = BINARY4(0101) --> int a = (0xHEX_(0101)); // COMBINE() is
explained first;

It seems that the order of macro explanation is different in VC7
and GCC.
Well, which one is right? Does standard C support recursive macro
explanation (just like what VC7 does)?
If I want to write such a convert macro which can be compiled by
VC7 and GCC, how should I do?
Thanks a lot!
 
J

Jordan Abel

Hi there:
These days I came to a problem that I failed to convert a binary
number to a hex number using a macro. For example:

int a = BINARY4(0101) will become int a = 0x5;
int a = BINARY8(0001,0101) will become int a = 0x15;
...etc.

I've written the following macros:

#define HEX_0000 0
#define HEX_0101 5
... ...
#define HEX_(a) HEX_ ## a
#define COMBINE(a) (0x ## a)
#define BINARY(a) COMBINE(HEX_(a))

These macros work all right in VC7, but when I compile the program
using VC8 or GCC-3.4.4, the result is wrong. When using GCC, the result
is:

int a = BINARY4(0101) --> int a = (0xHEX_(0101)); // COMBINE() is
explained first;

It seems that the order of macro explanation is different in VC7
and GCC.
Well, which one is right? Does standard C support recursive macro
explanation (just like what VC7 does)?
If I want to write such a convert macro which can be compiled by
VC7 and GCC, how should I do?
Thanks a lot!

Certain things involving the token-pasting operator are
implementation-defined. Try wrapping it in more macros to be able to
make the precedence explicit. An extra level of indirection also seems
to help [i've also seen it help with the stringize operator]

This seems to work - Only tested with gcc, but it's probably hard to
screw up.

#define PASTE(a,b)a##b
#define PASTE2(a,b)PASTE(a,b)
#define x(y)y
#define HEX_(x)PASTE(HEX_,x)
#define Ox(x)PASTE(0x,x)
#define HEX_0100 4
#define HEX_0010 2
#define HEX(x)
#define BINARY4(x)Ox(HEX_(x))
#define BINARY8(x,y)PASTE2(BINARY4(x),HEX_(y))
BINARY4(0100)
BINARY8(0100,0010)
 
M

Micah Cowan

Certain things involving the token-pasting operator are
implementation-defined. Try wrapping it in more macros to be able to
make the precedence explicit. An extra level of indirection also seems
to help [i've also seen it help with the stringize operator]

More macros aren't necessary. The level of indirection is.
This seems to work - Only tested with gcc, but it's probably hard to
screw up.

#define PASTE(a,b)a##b
#define PASTE2(a,b)PASTE(a,b)
#define x(y)y
#define HEX_(x)PASTE(HEX_,x)
#define Ox(x)PASTE(0x,x)
#define HEX_0100 4
#define HEX_0010 2
#define HEX(x)
#define BINARY4(x)Ox(HEX_(x))
#define BINARY8(x,y)PASTE2(BINARY4(x),HEX_(y))
BINARY4(0100)
BINARY8(0100,0010)

Playing around until it works is not usually a good way to generate
portable code. In your case, it has. But note that the x() macro above
isn't actually used anywhere, so it could be eliminated. Also, you
could eliminate HEX_() and 0x() by simply using PASTE2() directly:
it's the indirection that forces the arguments to be recursively
expanded. When a parameter is encountered after a # or next to a ##,
it will /not/ be macro-replaced, which is why the original
COMBINE(HEX_(a)) /must/ produce 0xHEX_(a) (which, since it isn't
defined as a macro, won't be further replaced).

AIUI, this has never been implementation-defined behavior, and VC7 was
wrong to produce "correct" results.

-Micah
 
J

Jordan Abel

Certain things involving the token-pasting operator are
implementation-defined. Try wrapping it in more macros to be able to
make the precedence explicit. An extra level of indirection also seems
to help [i've also seen it help with the stringize operator]

More macros aren't necessary. The level of indirection is.
This seems to work - Only tested with gcc, but it's probably hard to
screw up.

#define PASTE(a,b)a##b
#define PASTE2(a,b)PASTE(a,b)
#define x(y)y
#define HEX_(x)PASTE(HEX_,x)
#define Ox(x)PASTE(0x,x)
#define HEX_0100 4
#define HEX_0010 2
#define HEX(x)
#define BINARY4(x)Ox(HEX_(x))
#define BINARY8(x,y)PASTE2(BINARY4(x),HEX_(y))
BINARY4(0100)
BINARY8(0100,0010)

Playing around until it works is not usually a good way to generate
portable code. In your case, it has. But note that the x() macro above
isn't actually used anywhere, so it could be eliminated. Also, you
could eliminate HEX_() and 0x() by simply using PASTE2() directly:
it's the indirection that forces the arguments to be recursively
expanded. When a parameter is encountered after a # or next to a ##,
it will /not/ be macro-replaced, which is why the original
COMBINE(HEX_(a)) /must/ produce 0xHEX_(a) (which, since it isn't
defined as a macro, won't be further replaced).

I tried to use HEX_ and Ox to provide the extra level of indirection -
any idea why it didn't work?
 
J

Jordan Abel

Jordan Abel said:
Hi there:
These days I came to a problem that I failed to convert a binary
number to a hex number using a macro. For example:

int a = BINARY4(0101) will become int a = 0x5;
int a = BINARY8(0001,0101) will become int a = 0x15;
...etc.

I've written the following macros:

#define HEX_0000 0
#define HEX_0101 5
... ...
#define HEX_(a) HEX_ ## a
#define COMBINE(a) (0x ## a)
#define BINARY(a) COMBINE(HEX_(a))

Certain things involving the token-pasting operator are
implementation-defined. Try wrapping it in more macros to be able to
make the precedence explicit. An extra level of indirection also seems
to help [i've also seen it help with the stringize operator]

More macros aren't necessary. The level of indirection is.
This seems to work - Only tested with gcc, but it's probably hard to
screw up.

#define PASTE(a,b)a##b
#define PASTE2(a,b)PASTE(a,b)
#define x(y)y
#define HEX_(x)PASTE(HEX_,x)
#define Ox(x)PASTE(0x,x)
#define HEX_0100 4
#define HEX_0010 2
#define HEX(x)
#define BINARY4(x)Ox(HEX_(x))
#define BINARY8(x,y)PASTE2(BINARY4(x),HEX_(y))
BINARY4(0100)
BINARY8(0100,0010)

Playing around until it works is not usually a good way to generate
portable code. In your case, it has. But note that the x() macro above
isn't actually used anywhere, so it could be eliminated. Also, you
could eliminate HEX_() and 0x() by simply using PASTE2() directly:
it's the indirection that forces the arguments to be recursively
expanded. When a parameter is encountered after a # or next to a ##,
it will /not/ be macro-replaced, which is why the original
COMBINE(HEX_(a)) /must/ produce 0xHEX_(a) (which, since it isn't
defined as a macro, won't be further replaced).

I tried to use HEX_ and Ox to provide the extra level of indirection -
any idea why it didn't work?

Also, why doesn't

#define PASTE(a,b) a/**/b

make it provide correct results in K&R mode? It's not particularly
important, but I was curious.
 
M

Micah Cowan

I thought you said it /did/ work. It does for me, and looks fine, if
verbose. I just meant you don't need the HEX_() and 0x() macros
weren't necessary: PASTE2() provides adequate indirection.
Also, why doesn't

#define PASTE(a,b) a/**/b

make it provide correct results in K&R mode? It's not particularly
important, but I was curious.

As to that... the Standard requires that comments be treated as a
single space. AFAIK, in K&R days it probably was up to the
implementation to decide whether this would result in "token pasting"
or a single space. Someone with a good deal more experience in K&R C
should probably speak up now.
 
J

Jordan Abel

I thought you said it /did/ work. It does for me, and looks fine, if
verbose. I just meant you don't need the HEX_() and 0x() macros
weren't necessary: PASTE2() provides adequate indirection.


As to that... the Standard requires that comments be treated as a
single space. AFAIK, in K&R days it probably was up to the
implementation to decide whether this would result in "token pasting"
or a single space. Someone with a good deal more experience in K&R C
should probably speak up now.

except it ends up 0x4 2 not 0x 4 2
 
J

Jordan Abel

I thought you said it /did/ work. It does for me, and looks fine, if
verbose. I just meant you don't need the HEX_() and 0x() macros
weren't necessary: PASTE2() provides adequate indirection.

I was wondering why HEX_() and Ox() alone did not provide adequate
indirection. PASTE2 was added after those failed.
 
M

Micah Cowan

Jordan Abel said:
I was wondering why HEX_() and Ox() alone did not provide adequate
indirection. PASTE2 was added after those failed.

Well, your BINARY4() doesn't use PASTE2: only HEX_() and Ox() (BTW,
that's a /really/ misleading name...), and it works fine.

Now, trying

#define BINARY8(x,y) PASTE(BINARY4(x),HEX_(y))

wouldn't work, because the arguments won't be macro-expanded before
the pasting occurs. It will try to paste exactly (unexpanded):

BINARY4(x)

with

HEX_(y)

..

Since the ) token pasted against the HEX_ token
doesn't yield a single resulting token, so UB results (and, at least
on my system, an error).

Is that what you wanted to know?
 

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
474,175
Messages
2,570,945
Members
47,492
Latest member
gabbywilliam

Latest Threads

Top