C macro to declare unsigned long from "ABCD"

A

Andre

Dear all,

I would like to handle a table of 4-byte long strings by just declaring
them as an array of unsigned 32 bit values.
Of course, this can be done manually, but it would be great if a macro
XY existed, that, for example, from
XY("ABCD") would generate a unsigned 32bit declaration like 0x41424344

Is anybody aware of a macro that does this?

Best regards,

Andre
 
J

JohnF

Andre said:
I would like to handle a table of 4-byte long strings by just declaring
them as an array of unsigned 32 bit values.
Of course, this can be done manually, but it would be great if a macro
XY existed, that, for example, from
XY("ABCD") would generate a unsigned 32bit declaration like 0x41424344
Is anybody aware of a macro that does this? Best regards, Andre

Maybe just try...
#include <stdio.h>
#define uint unsigned int
#define XY(s) (((uint)(*(s+3))) + 256*( ((uint)(*(s+2))) \
+ 256*( ((uint)(*(s+1))) + 256*((uint)(*s)) )))
int main ( int argc, char *argv[] ) {
unsigned int xy = XY((argc>1?argv[1]:"ABCD"));
printf("%08X\n",xy); }
 
J

Jens Thoms Toerring

Andre said:
I would like to handle a table of 4-byte long strings by just declaring
them as an array of unsigned 32 bit values.
Of course, this can be done manually, but it would be great if a macro
XY existed, that, for example, from
XY("ABCD") would generate a unsigned 32bit declaration like 0x41424344

Not sure what you mean by "declaration" here but perhaps some-
thing like this is what you're looking for

#include <stdio.h>
#include <stdint.h>

#define XY( x ) ( x[0] << 24 | x[1] << 16 | x[2] << 8 | x[3] )

int main( void )
{
uint32_t x = XY( "ABCD" );
printf( "0x%08x\n", x );
return 0;
}

Of course, the normal caveats apply, i.e. your relying on a
certain character encoding, that a char has 8 bits etc. And
that the macro argument is really something that is a pointer
to an array-like object with at least four chars.

Regards, Jens
 
A

Andre

Andre said:
I would like to handle a table of 4-byte long strings by just declaring
them as an array of unsigned 32 bit values.
Of course, this can be done manually, but it would be great if a macro
XY existed, that, for example, from
XY("ABCD") would generate a unsigned 32bit declaration like 0x41424344
Is anybody aware of a macro that does this? Best regards, Andre

Maybe just try...
#include<stdio.h>
#define uint unsigned int
#define XY(s) (((uint)(*(s+3))) + 256*( ((uint)(*(s+2))) \
+ 256*( ((uint)(*(s+1))) + 256*((uint)(*s)) )))
int main ( int argc, char *argv[] ) {
unsigned int xy = XY((argc>1?argv[1]:"ABCD"));
printf("%08X\n",xy); }

Cool, works.
I had expected that it wouldn't because of alignment...
 
N

Noob

Andre said:
I would like to handle a table of 4-byte long strings by just declaring
them as an array of unsigned 32 bit values.
Of course, this can be done manually, but it would be great if a macro
XY existed, that, for example, from
XY("ABCD") would generate a unsigned 32bit declaration like 0x41424344

Is anybody aware of a macro that does this?

First stab, no cigar :-(

#define XY(s) ( s[0]<<24 | s[1]<<16 | s[2]<<8 | s[3] )
unsigned arr[] =
{
XY("ABCD"),
XY("EFGH"),
XY("IJKL"),
};

$ gcc mini.c
mini.c:4:3: error: initializer element is not constant
mini.c:4:3: error: (near initialization for 'arr[0]')
mini.c:5:3: error: initializer element is not constant
mini.c:5:3: error: (near initialization for 'arr[1]')
mini.c:6:3: error: initializer element is not constant
mini.c:6:3: error: (near initialization for 'arr[2]')
 
N

Noob

Noob said:
Andre said:
I would like to handle a table of 4-byte long strings by just declaring
them as an array of unsigned 32 bit values.
Of course, this can be done manually, but it would be great if a macro
XY existed, that, for example, from
XY("ABCD") would generate a unsigned 32bit declaration like 0x41424344

Is anybody aware of a macro that does this?

First stab, no cigar :-(

#define XY(s) ( s[0]<<24 | s[1]<<16 | s[2]<<8 | s[3] )
unsigned arr[] =
{
XY("ABCD"),
XY("EFGH"),
XY("IJKL"),
};

$ gcc mini.c
mini.c:4:3: error: initializer element is not constant
mini.c:4:3: error: (near initialization for 'arr[0]')
mini.c:5:3: error: initializer element is not constant
mini.c:5:3: error: (near initialization for 'arr[1]')
mini.c:6:3: error: initializer element is not constant
mini.c:6:3: error: (near initialization for 'arr[2]')

There is a work-around if you're willing to break the string up.

#define YX(A,B,C,D) ( A<<24 | B<<16 | C << 8 | D )
unsigned arr[] =
{
YX('A','B','C','D'),
YX('E','F','G','H'),
};

$ gcc -Wall -Wextra -Os -S mini.c
$ cat mini.s
.file "mini.c"
..globl _arr
.data
.align 4
_arr:
.long 1094861636
.long 1162233672


NB: 1094861636 = 0x41424344 and 1162233672 = 0x45464748
 
B

Ben Bacarisse

Andre said:
I would like to handle a table of 4-byte long strings by just
declaring them as an array of unsigned 32 bit values.

A word of warning... The result won't be a string even, when you
construct a character pointer to the int, because there will be no null
terminator.

<snip>
 
E

Eric Sosman

Dear all,

I would like to handle a table of 4-byte long strings by just declaring
them as an array of unsigned 32 bit values.
Of course, this can be done manually, but it would be great if a macro
XY existed, that, for example, from
XY("ABCD") would generate a unsigned 32bit declaration like 0x41424344

Is anybody aware of a macro that does this?

Others have offered macros that produce values from the
characters of strings, but note that the results are not
integer constant expressions. You could use them this way:

if (XY(string) == XY("ABCD")) ...

but not this way:

switch(XY(string)) {
case XY("ABCD"): ...
case XY("WXYZ"): ...
}

If this doesn't satisfy your need, perhaps you could describe
your situation more concretely. Someone's likely to come up with
another approach if it's needed.
 
J

James Kuyper

Noob said:
There is a work-around if you're willing to break the string up.

#define YX(A,B,C,D) ( A<<24 | B<<16 | C << 8 | D )
unsigned arr[] =
{
YX('A','B','C','D'),
YX('E','F','G','H'),
};

If the OP is prepared to step outside of portable C:

unsigned arr[] =
{
'ABCD',
'EFGH'
};

He specified in the Subject: header that he's looking for unsigned long,
not unsigned. UINT_MAX could be as small as 0xFFFF, in which case it
would be absolutely guaranteed that this array does not contain the
values he's looking for.

You should identify precisely what the portability issue is. This code
must be accepted by any conforming C compiler - that's not what the
problem is. However, while C does allow character constants to contain
multiple characters, the value of such constants is an
implementation-defined int value. Since INT_MAX could be as small as
0x7FFF, on many implementations it would be impossible to form a
character constant with the right value. Even on implementations where
int is 32 bits, the value could be anything from INT_MIN to INT_MAX.
Without even considering systems which use character encoding
incompatible with ASCII, plausible values for 'ABCD' other than
0x41424344 include 0x44434241, 0x4142, 0x4443, 0x41, and 0x44.
 
B

BartC

Andre said:
Dear all,

I would like to handle a table of 4-byte long strings by just declaring
them as an array of unsigned 32 bit values.

Not sure if this is useful, but the following array of 4-char strings is
also accessed here via an int pointer (ie. an int array). (Substitute an
unsigned long here.)

#include <stdio.h>

char shortstrings[][4]={"ONE","TWO","THRE","FOUR","FIVE"};
int *ishortstrings=shortstrings;

int main(void)
{
int i;

for(i=0; i<5; ++i){
printf("%d:<%04X> <%.4s>\n", i, ishortstrings,
(char*)&ishortstrings );
}

}
 
K

Keith Thompson

JohnF said:
Andre said:
I would like to handle a table of 4-byte long strings by just declaring
them as an array of unsigned 32 bit values.
Of course, this can be done manually, but it would be great if a macro
XY existed, that, for example, from
XY("ABCD") would generate a unsigned 32bit declaration like 0x41424344
Is anybody aware of a macro that does this? Best regards, Andre

Maybe just try...
#include <stdio.h>
#define uint unsigned int
#define XY(s) (((uint)(*(s+3))) + 256*( ((uint)(*(s+2))) \
+ 256*( ((uint)(*(s+1))) + 256*((uint)(*s)) )))
int main ( int argc, char *argv[] ) {
unsigned int xy = XY((argc>1?argv[1]:"ABCD"));
printf("%08X\n",xy); }

Why is "uint" a macro? Make it a typedef:

typedef unsigned int uint;

Or just use "unsigned int":

#define XY(s) (((unsigned int)(*(s+3))) + \
256*(((unsigned int)(*(s+2))) + \
256*(((unsigned int)(*(s+1))) + \
256*((unsigned int)(*s)))))
 
B

Ben Bacarisse

BartC said:
Andre said:
Dear all,

I would like to handle a table of 4-byte long strings by just
declaring them as an array of unsigned 32 bit values.

Not sure if this is useful, but the following array of 4-char strings
is also accessed here via an int pointer (ie. an int
array). (Substitute an unsigned long here.)

#include <stdio.h>

char shortstrings[][4]={"ONE","TWO","THRE","FOUR","FIVE"};
int *ishortstrings=shortstrings;

That may well have alignment problems.

This may work better:

union {
char cv[sizeof(unsigned long)];
unsigned long lv;
} longs[] = { "ONE", "TWO, "THRE", "FOUR", "FIVE" };
 
T

Tim Rentsch

James Kuyper said:
Noob said:
There is a work-around if you're willing to break the string up.

#define YX(A,B,C,D) ( A<<24 | B<<16 | C << 8 | D )
unsigned arr[] =
{
YX('A','B','C','D'),
YX('E','F','G','H'),
};

If the OP is prepared to step outside of portable C:

unsigned arr[] =
{
'ABCD',
'EFGH'
};

He specified in the Subject: header that he's looking for unsigned long,
not unsigned. UINT_MAX could be as small as 0xFFFF, in which case it
would be absolutely guaranteed that this array does not contain the
values he's looking for.

You should identify precisely what the portability issue is. This code
must be accepted by any conforming C compiler - [snip]

That's wrong, in exactly the case you mention. An implementation
that has 16 bit ints could reject it because the value isn't in
the range of values representable in type 'int'.
 
T

Tim Rentsch

Keith Thompson said:
JohnF said:
Andre said:
I would like to handle a table of 4-byte long strings by just declaring
them as an array of unsigned 32 bit values.
Of course, this can be done manually, but it would be great if a macro
XY existed, that, for example, from
XY("ABCD") would generate a unsigned 32bit declaration like 0x41424344
Is anybody aware of a macro that does this? Best regards, Andre

Maybe just try...
#include <stdio.h>
#define uint unsigned int
#define XY(s) (((uint)(*(s+3))) + 256*( ((uint)(*(s+2))) \
+ 256*( ((uint)(*(s+1))) + 256*((uint)(*s)) )))
int main ( int argc, char *argv[] ) {
unsigned int xy = XY((argc>1?argv[1]:"ABCD"));
printf("%08X\n",xy); }

Why is "uint" a macro? Make it a typedef:

typedef unsigned int uint;

Or just use "unsigned int":

#define XY(s) (((unsigned int)(*(s+3))) + \
256*(((unsigned int)(*(s+2))) + \
256*(((unsigned int)(*(s+1))) + \
256*((unsigned int)(*s)))))

Why use a type name at all?

#define XY(s) ( ( (0*256UL + 1) * 256 + 2) * 256 + 3)
 
K

Kaz Kylheku

Dear all,

I would like to handle a table of 4-byte long strings by just declaring
them as an array of unsigned 32 bit values.
Of course, this can be done manually, but it would be great if a macro
XY existed, that, for example, from
XY("ABCD") would generate a unsigned 32bit declaration like 0x41424344

Is anybody aware of a macro that does this?

I would recommend giving up on XY("ABCD"), and instead do:

#define FOURCC(A,B,C,D) ((unsigned long) (A) << 24 | \
(unsigned long) (B) << 16 | \
(unsigned) (C) << 8 | (D))


Then call it like this, with character constants:

FOURCC('A', 'B', 'C', 'D')
 
A

Andre

Cool, I like this very much, and it does indeed work for VisualDSP (a
compiler for a DSP processor).

However, GNU C does not like it...

Best regards,

Andre


Noob said:
There is a work-around if you're willing to break the string up.

#define YX(A,B,C,D) ( A<<24 | B<<16 | C<< 8 | D )
unsigned arr[] =
{
YX('A','B','C','D'),
YX('E','F','G','H'),
};

If the OP is prepared to step outside of portable C:

unsigned arr[] =
{
'ABCD',
'EFGH'
};

<snip>
 
A

Andre

I have to correct myself: GNU does accept it!
Thanks a lot!

best regards,

Andre

Cool, I like this very much, and it does indeed work for VisualDSP (a
compiler for a DSP processor).

However, GNU C does not like it...

Best regards,

Andre


Noob said:
There is a work-around if you're willing to break the string up.

#define YX(A,B,C,D) ( A<<24 | B<<16 | C<< 8 | D )
unsigned arr[] =
{
YX('A','B','C','D'),
YX('E','F','G','H'),
};

If the OP is prepared to step outside of portable C:

unsigned arr[] =
{
'ABCD',
'EFGH'
};

<snip>
 

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

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top