By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
455,113 Members | 1,409 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 455,113 IT Pros & Developers. It's quick & easy.

convert a char[4] (binary) to an unsigned long

P: n/a
Hi all,

I want to convert a char[4] (binary) to an unsigned long. How can I do
this?

Thanks,
Vincent

Aug 5 '05 #1
Share this Question
Share on Google+
19 Replies


P: n/a
Vincent sade:
Hi all,

I want to convert a char[4] (binary) to an unsigned long. How can I do
this?

Thanks,
Vincent


assert(sizeof(long) == 4);
char b[4] = {0x01,0x02,0x03,0x04};
unsigned long a = 0;
a |= (b[0] << 24);
a |= (b[1] << 16);
a |= (b[2] << 8);
a |= b[3];

But if you have MSB in b[3] then you should reverse the order.
Beware of big endian and little endian.

Tobias
--
IMPORTANT: The contents of this email and attachments are confidential
and may be subject to legal privilege and/or protected by copyright.
Copying or communicating any part of it to others is prohibited and may
be unlawful.
Aug 5 '05 #2

P: n/a
Vincent wrote:
Hi all,

I want to convert a char[4] (binary) to an unsigned long. How can I do
this?

Thanks,
Vincent


I don't think this is possible without knowing the endian-ness of the
machine. Maybe someone will correct me.

If the char[4] came from the machine, then you could probably do a
reinterpret_cast, but I'm almost positive it won't be portable.

// assume this has your binary unsigned long
extern char ul_bin[4];
unsigned long ul = *reinterpret_cast<unsigned long *>(ul_bin);

--John Ratliff
Aug 5 '05 #3

P: n/a
The program will have to work on MS Windows 2000. The char[4] is a set
of characters, read from a file.

I hope this will help you answering my question.

Aug 5 '05 #4

P: n/a

Vincent skrev:
Hi all,

I want to convert a char[4] (binary) to an unsigned long. How can I do
this?

Thanks,
Vincent


Use memcpy:

unsigned long ChararrToLong(const char * const src)
{
unsigned long dest;
memcpy(&dest, src, sizeof(dest));
return dest;
}
This may be what you want or not. If you depend on the chars being put
in a specific order into the unsigned long, you might want to do some
byte-swapping while copying.

Aug 5 '05 #5

P: n/a
Vincent sade:
The program will have to work on MS Windows 2000. The char[4] is a set
of characters, read from a file.

I hope this will help you answering my question.


Find out what format the long's are stored in, what endianness.

long l = 0x04030201

can be stored as

Big endian: 0x04030201
Little endian: 0x01020304

Or any random order you desire in your file, but if you don't
know the byte order, how will you be able to read them back correctly?

http://en.wikipedia.org/wiki/Endianess

Tobias
--
IMPORTANT: The contents of this email and attachments are confidential
and may be subject to legal privilege and/or protected by copyright.
Copying or communicating any part of it to others is prohibited and may
be unlawful.
Aug 5 '05 #6

P: n/a
Vincent wrote:
The program will have to work on MS Windows 2000. The char[4] is a set
of characters, read from a file.

I hope this will help you answering my question.


It will only work if the char[4] read from Windows was created on a
machine with endian-ness the same as Windows 2000 (little endian for
x86) written in endian correct order.

In other words, if you wrote an unsigned long created on a machine to a
file, and then wanted to read that unsigned long from a char[4] byte
array on the same machine, the reinterpret_cast would work. If this file
is created on some other machine, you can only know if it would work if
you know the endian-ness of the machine which created the file.

A question though, why are you reading an unsigned long into a char[4]
array anyways? Why not read it directly into an unsigned long? Or, how
does the unsigned long get written in the first place? Maybe you should
consider writing it as a string instead and parsing the string back
using strtoul() instead.

--John Ratliff
Aug 5 '05 #7

P: n/a
On Fri, 05 Aug 2005 12:25:38 +0200, Tobias Blomkvist <vo**@void.void>
wrote in comp.lang.c++:
Vincent sade:
Hi all,

I want to convert a char[4] (binary) to an unsigned long. How can I do
this?

Thanks,
Vincent

assert(sizeof(long) == 4);


This doesn't actually solve the problem. And what happens if
sizeof(long) is 8, which it is on some 64 bit platforms?
char b[4] = {0x01,0x02,0x03,0x04};
unsigned long a = 0;
a |= (b[0] << 24);
The problem here is that b[0] is promoted to either int or unsigned
int before it is shifted. There are still a large number of platforms
where long has 32 bits but int has only 16. Shifting by 24 on such a
platform is undefined behavior, and will almost certainly give the
wrong results.

Perhaps you think that the extra step of initializing 'a' to 0 and
using |= forces b[0] to be promoted to unsigned long. It most
certainly does not. b[0] is promoted to either int or unsigned int,
the shift is performed and assuming there is no undefined behavior or
the program continues regardless, the resulting unsigned int value is
only then promoted to unsigned long.

Should be:

unsigned long a = ((unsigned long)b1 << 24);
a |= (b[1] << 16);
Same cast here.
a |= (b[2] << 8);
a |= b[3];
The last two do not need the cast. Except maybe platforms where
unsigned char and int both have 16 bits, and the value in the unsigned
char is greater than 255. And yes, there are platforms like this that
actually have C++ compilers.
But if you have MSB in b[3] then you should reverse the order.
Beware of big endian and little endian.

Tobias


--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Aug 6 '05 #8

P: n/a
John Ratliff wrote:
I don't think this is possible without knowing the endian-ness of the
machine. Maybe someone will correct me.


int x = 1;

endianness = * (char *) & x ? LITTLE_ENDIAN : BIG_ENDIAN;

Some compilers (GCC for sure) can optimize away code using this expression.

e.g.

int x = 1;
if ( * (char *) & x )
{
... little endian code ...
... optimized away when compiled for a little endian machine ...
} else
{
... big endian code ...
... optimized away when compiled for a big endian machine ...
}
Aug 6 '05 #9

P: n/a
Vincent wrote:
Hi all,

I want to convert a char[4] (binary) to an unsigned long. How can I do
this?

See:
http://groups-beta.google.com/group/...6?dmode=source

http://groups.google.com/group/comp....F-8&edition=us
Aug 6 '05 #10

P: n/a
Jack Klein sade:

assert(sizeof(long) == 4);

This doesn't actually solve the problem. And what happens if
sizeof(long) is 8, which it is on some 64 bit platforms?


It fails.
char b[4] = {0x01,0x02,0x03,0x04};
unsigned long a = 0;
a |= (b[0] << 24);

The problem here is that b[0] is promoted to either int or unsigned
int before it is shifted. There are still a large number of platforms
where long has 32 bits but int has only 16. Shifting by 24 on such a
platform is undefined behavior, and will almost certainly give the
wrong results.


True. An
assert(sizeof(int) == 4);
would secure the code.

The last two do not need the cast. Except maybe platforms where
unsigned char and int both have 16 bits, and the value in the unsigned
char is greater than 255. And yes, there are platforms like this that
actually have C++ compilers.


On the other hand, writing code like this, you must be aware. Why do
you think I used assert?

Tobias
--
IMPORTANT: The contents of this email and attachments are confidential
and may be subject to legal privilege and/or protected by copyright.
Copying or communicating any part of it to others is prohibited and may
be unlawful.
Aug 6 '05 #11

P: n/a
"Gianni Mariani"
int x = 1;

endianness = * (char *) & x ? LITTLE_ENDIAN : BIG_ENDIAN;


Can someone explain how this expression works? std::reverse is useful for
changing endiann type.

Fraser.
Aug 8 '05 #12

P: n/a
"Fraser Ross"
"Gianni Mariani"
int x = 1;

endianness = * (char *) & x ? LITTLE_ENDIAN : BIG_ENDIAN;


Can someone explain how this expression works? std::reverse is useful for
changing endiann type.

Fraser.


I see it now. A static_cast would be more understandable. For a moment I
thought there was a use of a bit-wise operator.

Fraser.
Aug 8 '05 #13

P: n/a

"Fraser Ross"
I see it now. A static_cast would be more understandable.


No, reinterpret_cast is required.

Fraser.
Aug 8 '05 #14

P: n/a
&x points to a number of bytes which contain (on a big endian machine,
LSB is at highest byte address) 0, 0, ... , 1, and (on a little endian
machine, LSB is at lowest byte address) 1, 0, ... 0

Interpreting the pointer as a char * and getting the byte pointed to
will return the contents of the lowest addressed byte of the word,
which will be 0 for big endian machines and 1 for little endian
machines.

Optimising out the code is presumably a result of gcc recognising that
particular pattern - it would be rather dangerous if you were cross
compiling!

Aug 8 '05 #15

P: n/a
Thanks for this suggestion. It works! Somewhere else in my script, I
have to convert an unsigned long to a char[4]. I tried to use memcpy to
create a LongtoChararr function, but i failed. I'm not very familiar
with memcpy. Can you help me again?
Hans wrote:
Vincent skrev:
Hi all,

I want to convert a char[4] (binary) to an unsigned long. How can I do
this?

Thanks,
Vincent


Use memcpy:

unsigned long ChararrToLong(const char * const src)
{
unsigned long dest;
memcpy(&dest, src, sizeof(dest));
return dest;
}
This may be what you want or not. If you depend on the chars being put
in a specific order into the unsigned long, you might want to do some
byte-swapping while copying.


Aug 8 '05 #16

P: n/a
Tobias Blomkvist wrote:
Jack Klein sade:

assert(sizeof(long) == 4);


This doesn't actually solve the problem. And what happens if
sizeof(long) is 8, which it is on some 64 bit platforms?


It fails.
char b[4] = {0x01,0x02,0x03,0x04};
unsigned long a = 0;
a |= (b[0] << 24);

The problem here is that b[0] is promoted to either int or unsigned
int before it is shifted. There are still a large number of platforms
where long has 32 bits but int has only 16. Shifting by 24 on such a
platform is undefined behavior, and will almost certainly give the
wrong results.


True. An
assert(sizeof(int) == 4);
would secure the code.


Actually it wouldn't, eg. (8-bit signed char):
char b[4] = { 0x01, 0x02, 0x03, 0x99 };

Then 0x01020300 | 0x99 will become 0x01020300 | 0xFFFFFF99
which is not the desired result. You have to make the
chars unsigned before you apply bit operations to them.

Aug 8 '05 #17

P: n/a
Vincent wrote:
Thanks for this suggestion. It works! Somewhere else in my script, I
have to convert an unsigned long to a char[4]. I tried to use memcpy to
create a LongtoChararr function, but i failed. I'm not very familiar
with memcpy. Can you help me again?


If byte order is not essential, you can do reinterpret_cast again.

unsigned long ul = 0xFEDCBA98;
char *ptr = reinterpret_cast<char *>(&ul);

Depending upon endianness, you will end up with one of these:
ptr[] = {0xFE, 0xDC, 0xBA, 0x98}; // big endian machine
ptr[] = {0x98, 0xBA, 0xDC, 0xFE}; // little endian machine

Note if an unsigned long is not 4 bytes on the platform you're using,
you will end up with a different sized array.

If you really want to use memcpy,

unsigned long ul = 0xFEDCBA98;
char ptr[sizeof(unsigned long)];

memcpy(ptr, &ul, sizeof(unsigned long));

--John Ratliff
Aug 9 '05 #18

P: n/a
In message <11**********************@f14g2000cwb.googlegroups .com>,
ThosRTanner <tt******@bloomberg.net> writes
&x points to a number of bytes which contain (on a big endian machine,
LSB is at highest byte address) 0, 0, ... , 1, and (on a little endian
machine, LSB is at lowest byte address) 1, 0, ... 0

Interpreting the pointer as a char * and getting the byte pointed to
will return the contents of the lowest addressed byte of the word,
which will be 0 for big endian machines and 1 for little endian
machines.

Optimising out the code is presumably a result of gcc recognising that
particular pattern - it would be rather dangerous if you were cross
compiling!


It's rather dangerous anyway if your target platform has
sizeof(int)==sizeof(char).

--
Richard Herring
Aug 15 '05 #19

P: n/a

Vincent wrote:
Hi all,

I want to convert a char[4] (binary) to an unsigned long. How can I do
this?


My suggestion is to:
- always use big-endian regardless of platform
- use something like this:

const size_t CHAR_BITS = 8; // or whatever it is on your system

unsigned long makeLong( const char* data )
{
unsigned long result = 0;
for ( int i=0; i<4; ++i )
{
result <<= CHAR_BITS;
result |= data[i];
}
}

that will work whenever sizeof(long) >= 4 or there are sufficient
trailing 0 bytes that overflow does not occur.

Aug 15 '05 #20

This discussion thread is closed

Replies have been disabled for this discussion.