I have a value (long for example) and I want to split into an array of
char.
Doing so:
unsigned long l = 0xAABBCCDD;
unsigned char *bytes = (unsigned char*)& l;
works, but is it secure? Or there is a better method?
Tnx.
Daniele.
This works, but keep in mind that this code is platform dependend.
bytes[0] can be 0xAA, 0xDD or probably any other value, depending on the
endianess of the CPU.
Further drawback: You dont have any size information of the bytes array.
Slightly better would be:
union
{
long l;
bytes b[4];
} u;
or
union
{
long l;
struct
{
b1:8;
b2:8;
b3:8;
b4:8;
} b;
} u;
Regards,
Helge
What do you mean "secure"???
You could do this:
unsigned long l = 0xAABBCCDD;
unsigned char *bytes = reinterpret_cast< unsigned char* > ( & l );
> I have a value (long for example) and I want to split into an array of
> char.
>
> Doing so:
>
> unsigned long l = 0xAABBCCDD;
> unsigned char *bytes = (unsigned char*)& l;
>
> works, but is it secure?
Provided l lifetime is same or longer than that of bytes.
> Or there is a better method?
Your method ignores padding bits (if any, normally none on popular x86
and x86-64 platforms) and byte order. http://en.wikipedia.org/wiki/Endianness
To make it byte order insensitive and ignore any padding bits you
could do:
#include <stdio.h>
#include <limits.h>
template<class T>
void asBytes(T t, unsigned char* bytes)
{
for(int i = 0; i != sizeof t; ++i)
bytes[i] = static_cast<unsigned char>(t >> i * CHAR_BIT &
0xff);
}
template<class T>
void fromBytes(unsigned char const* bytes, T* t)
{
*t = 0;
for(int i = 0; i != sizeof t; ++i)
*t |= bytes[i] << CHAR_BIT * i;
}
int main()
{
long l = 0x12345678;
unsigned char bytes[sizeof l];
asBytes(l, bytes);
long m;
fromBytes(bytes, &m);
printf("%lx -> %lx\n", l, m);
}
Obviously, the above two functions only work with integer types.
--
Max
This is exactly what I need.
Thanks Max!
Daniele.
> Barzo wrote:
>> Hi,
>>
>> I have a value (long for example) and I want to split into an array of
>> char.
>>
>> Doing so:
>>
>> unsigned long l = 0xAABBCCDD;
>> unsigned char *bytes = (unsigned char*)& l;
>>
>> works, but is it secure? Or there is a better method?
>>
>> Tnx.
>> Daniele.
>
> This works, but keep in mind that this code is platform dependend.
> bytes[0] can be 0xAA, 0xDD or probably any other value, depending on the
> endianess of the CPU.
>
> Further drawback: You dont have any size information of the bytes array.
The size is equal to sizeof(unsigned long).
> Slightly better would be:
>
> union
> {
> long l;
> bytes b[4];
> } u;
I don't consider that better. It's abuse of unions, which are not supposed
to be used like that. That's what casts (in this case reinterpret_cast) are
for.
And even better would be to not make assumptions about the size of long:
union u
{
long l;
unsigned char b[sizeof(long)];
};
--
Erik Wikström
[snip]
> Slightly better would be:
>
> union
> {
> long l;
> bytes b[4];
>
> } u;
>
> or
>
> union
> {
> long l;
> struct
> {
> b1:8;
> b2:8;
> b3:8;
> b4:8;
> } b;
>
> } u;
It is not better, its worse. unions can only be legally accessed as
the type they were last written with. It often works the union way,
but reinterpret_cast gives you better guarantees standardwise.
/Peter
> > Doing so:
> > unsigned long l = 0xAABBCCDD;
> > unsigned char *bytes = (unsigned char*)& l;
> > works, but is it secure? Or there is a better method?
Actually, whether it works or not depends on the definition of
"works". The problem hasn't been specified enough to say.
> This works, but keep in mind that this code is platform
> dependend. bytes[0] can be 0xAA, 0xDD or probably any other
> value, depending on the endianess of the CPU.
Endianness isn't the only issue; size can also play a role.
I've actually worked on systems where bytes[0] would be 0xBB,
and I'm aware of ones where it would be 0x00 or 0x15 (both still
being sold).
> Further drawback: You dont have any size information of the
> bytes array. Slightly better would be:
> union
> {
> long l;
> bytes b[4];
> } u;
That's formally worse, since it results in undefined behavior if
you access b when the last value was written to l. (In
practice, which is better depends on the compiler---some
compilers ignore aliasing which results from a
reinterpret_cast.)
> or
> union
> {
> long l;
> struct
> {
> b1:8;
> b2:8;
> b3:8;
> b4:8;
> } b;
> } u;
That is completely implementation defined. Some compilers will
lay out the first bit fields from LSB to MSB, others from MSB to
LSB. Some will put any padding at the top, others will put it
at the bottom. (I don't know of any which will insert padding
bits in the middle, but I think that would be legal as well.)
--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Whether with cast or union-cast, you have undefined behavior. Depending
on you architecture/compiler, the results may differs. If those won't
change, check your compiler's documentation and you may be able to use this.
The only way to reliably make this kind of conversion is to establish
your convention (such as where should go the MSB-LSB in your array) and
use an explicit construction:
unsigned l = 0xAABBCCDD;
assert(sizeof(l)==4);
//example in little endian
char bytes[4]={
(l>> 0)&0x0FF,
(l>> 8)&0x0FF,
(l>>16)&0x0FF,
(l>>24)&0x0FF
};
--
Michael
no. If bytes is an alias for unsigned char the it merely
results in implementation defined behaviour. unsigned char
is the exception to the usual "only read what you wrote to a
union". You can access any object as a array of unsigned char.
[caveat: this is true for C at least, I can't see why C++
would change it]
(In
> practice, which is better depends on the compiler---some
> compilers ignore aliasing which results from a
> reinterpret_cast.)
>
> > or
> > union
> > {
> > long l;
> > struct
> > {
> > b1:8;
> > b2:8;
> > b3:8;
> > b4:8;
> > } b;
> > } u;
>
> That is completely implementation defined.
yes
> Some compilers will
> lay out the first bit fields from LSB to MSB, others from MSB to
> LSB. Some will put any padding at the top, others will put it
> at the bottom. (I don't know of any which will insert padding
> bits in the middle, but I think that would be legal as well.)
--
Nick Keighley
The different branches of Arithmetic
- Ambition, Distraction, Uglification and Derision.
Alice in Wonderland.
note: the code uses CHAR_BIT which is usually 8.
Do actually want the integer broken up into chars
or octets (8-bit bytes)?
> Your method ignores padding bits (if any, normally none on popular x86
> and x86-64 platforms) and byte order.http://en.wikipedia.org/wiki/Endianness
>
> To make it byte order insensitive and ignore any padding bits you
> could do:
>
> #include <stdio.h>
> #include <limits.h>
>
> template<class T>
> void asBytes(T t, unsigned char* bytes)
> {
> for(int i = 0; i != sizeof t; ++i)
> bytes[i] = static_cast<unsigned char>(t >> i * CHAR_BIT &
> 0xff);
> }
That CHAR_BIT may make the code look more portable than it is. The
function will have surprising results if CHAR_BIT is anything but 8.
Consider for example a system with CHAR_BIT 32, and sizeof(unsigned
long) == 1. asBytes( 0xAABBCCDDul, bytes)
will end up writing a single byte with the value 0xDD.
Depending on which behaviour you want (native bytes or octets),
consider removing (& 0xff) or changing CHAR_BIT to 8.
Totally agree. Thanks.
--
Max
Octets please!
--
Max
Dang!!! From a seemingly simple problem to several inscrutable lines of
C. This is not to say you're wrong -- I think you're exactly right. It's
more of a comment on the state of things; the nature of C, the compiler
implementations, the uncertain length of words in memory, the
endian-ness of the CPUs, etc., etc.
It's a shame that we can't use more direct approaches. That we are
willing to accept complex solutions, or uncertain definitions for
fundamental things like byte,word, and long, seems to me a great shame.
Whatever happened to KISS?
Jack
>
> --
> Max
>
>
>
> It's a shame that we can't use more direct approaches. That we are
> willing to accept complex solutions, or uncertain definitions for
> fundamental things like byte,word, and long, seems to me a great shame.
> Whatever happened to KISS?
>
It ran into essential complexity driven by hardware. Java, on the other
hand, imposes specific size requirements, with the result that some
operations are extremely slow. For example, requiring every operation
on a double to use exactly 64 bits meant that the runtime support on
Intel hardware had to set the math processor to 64-bit mode rather than
its native 80-bit mode. This made it unusable for serious number
crunchers.
The true rule is "as simple as possible, but no simpler." And the
latter depends intimately on what the goal is. If the goal is absolute
determinism you pay a price in speed and, perhaps, size. C and C++ are
designed for flexibility so that speed and size don't suffer.
--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)
[...]
> > > Further drawback: You dont have any size information of the
> > > bytes array. Slightly better would be:
> > > union
> > > {
> > > long l;
> > > bytes b[4];
> > > } u;
> > That's formally worse, since it results in undefined
> > behavior if you access b when the last value was written to
> > l.
> no. If bytes is an alias for unsigned char the it merely
> results in implementation defined behaviour. unsigned char
> is the exception to the usual "only read what you wrote to a
> union".
Where does it say that? All I see is that "only one of the
members can be active at any time". Formally, I think that this
still remains undefined. Taking the address of l, casting it
to an unsigned char*, and accessing through that is legal, but
rather defeats the purpose of using a union.
In practice, of course, it will depend on the compiler. (Also,
I don't think the results are even "implementation defined".
More along the lines of "unspecified", or "very poorly
specified". But normally: "what the hardware gives you", which
may or may not be what is wanted.)
> You can access any object as a array of unsigned char.
> [caveat: this is true for C at least, I can't see why C++
> would change it]
C++ even extended it to encompass accessing it as an array of
char (which more or less means that plain char must be unsigned
if the machine is not 2's complement). But even something like:
union
{
char c1 ;
char c2 ;
} u ;
u.c1 = 'a' ;
putchar( u.c2 ) ;
is undefined behavior---the standard allows the implementation
to somehow maintain the information as to what the last stored
value was (except in some very special cases), and core dump if
you access via any other member.
(That was, at least, the concensus in the C committee, back in
the late 1980's. At least among some of the committee members.)
> C++ even extended it to encompass accessing it as an array of
> char (which more or less means that plain char must be unsigned
> if the machine is not 2's complement). But even something like:
>
> union
> {
> char c1 ;
> char c2 ;
> } u ;
> u.c1 = 'a' ;
> putchar( u.c2 ) ;
>
> is undefined behavior---the standard allows the implementation
> to somehow maintain the information as to what the last stored
> value was (except in some very special cases), and core dump if
> you access via any other member.
>
> (That was, at least, the concensus in the C committee, back in
> the late 1980's. At least among some of the committee members.)
The funny thing is that
struct s1 { char c; };
struct s2 { char c; };
union {
s1 m1;
s2 m2;
} u;
u.m1.c = 'a';
putchar(u.m2.c);
is conformant...
Yours,
--
Jean-Marc
Well, this is what C and C++ are - portable assembly languages (as the
original purpose of C was to write a portable operating system called
UNIX and C++ inherits C and builds upon it). It is portable because it
abstracts away the CPU instruction set, however, you are still dealing
with the bare metal.
--
Max
And the example of §9.5/2:
[Example:
void f()
{
union { int a; char* p; };
a = 1;
// ...
p = "Jennifer";
// ...
}
Here a and p are used like ordinary (nonmember) variables, but since
they are union members they have
the same address.]
The address is the same because of §9.5/1 "[...]Each data member is
allocated as if it were the sole member of a struct.[...]"
So there is a guarantee that the layout is the same for an union of 2
chars. The question is whether or not the compiler synchronized the data
at the data's address such that it is available through the second member.
We could believe it is so because of the guarantee that "[...]If a
POD-union contains several POD-structs that share a common initial
sequence, and if an object of this POD-union type contains one of the
POD-structs, it is permitted to inspect the common initial sequence of
any of POD-struct members[...]". Therefore there should be synchronization.
Unless the compiler can determine that the union doesn't contain such
POD struct with relevant initial sequence and inhibit the
synchronization of the memory.
--
Michael
Sigh. Well, I spent a lot of years converting Fortran programs to run on
new hardware. So I shouldn't complain over having to deal with things
like endian-ness. And you're right: It's much better to work with the
hardware rather than demanding conformance to some mental standard.
Still, I wish we could at least agree that a char is 8 bits, a short is
16, a long 32, etc. I'd lots rather know, up front, that I need to do a
multi-file global replace, than to find out the hard way that someone's
changed the rules on me.
Jack
How can it be both? If I'm programming in assembly language, I danged
well know what size the data I'm dealing with has. That's
well-understood but not portable.
If it's portable and "abstracts away the CPU instruction set," that's
portable but not well-understood. How can it be even close to assembly
language?
Jack
>
> --
> Max
> Pete Becker <pe...@versatilecoding.com> writes:
>> It ran into essential complexity driven by hardware. Java, on the other
>> hand, imposes specific size requirements, with the result that some
>> operations are extremely slow. For example, requiring every operation
>> on a double to use exactly 64 bits meant that the runtime support on
>> Intel hardware had to set the math processor to 64-bit mode rather than
>> its native 80-bit mode. This made it unusable for serious number
>> crunchers.
>
> »In older JVMs, floating-point calculations were always
> strict floating-point, meaning all values used during
> floating-point calculations are made in the IEEE-standard
> float or double sizes. This could sometimes result in a
> numeric overflow or underflow in the middle of a
> calculation, even if the end result would be a valid
> number. Since version 1.2 of the JVM, floating-point
> calculations do not require that all numbers used in
> computations are themselves limited to the standard float
> or double precision.
Well, as usual, wikipedia got the story half right. The JVM changed
behavior because the spec changed, which was because the original
requirement made floating-point math unusable for serious number
crunchers.
>
> However, for some applications, a programmer might require
> every platform to have precisely the same floating-point
> behavior, even if some platforms could handle more
> precision. In that case, the programmer can use the
> modifier strictfp to ensure that calculations are
> performed as in the earlier versions—only with floats and
> doubles.«
Yes, that's the Java rationalization. But remember, much of what you
hear about Java is marketing hype.
>
> Still, I wish we could at least agree that a char is 8 bits, a short is
> 16, a long 32, etc. I'd lots rather know, up front, that I need to do
> a multi-file global replace, than to find out the hard way that
> someone's changed the rules on me.
>
They're all at least that large, so if you write code that doesn't
exceed those limits it will be portable.
If you need exact sizes, there's int8_t, int16_t, etc. from <stdint.h>
(coming soon to a C++ standard near you). If the corresponding type
doesn't exist, the typedef won't be present, so you get a compile-time
error if the size you're relying on isn't supported.
Even today, if you need exact sizes you can enforce them:
#if SHORT_MAX == 32767
typedef short int_16;
#endif
The time when you really get into trouble is when you have to retrofit
requirements like that into code that wasn't written with those
requirements in mind.
Maybe, before performs the conversion, check if the platform is little
or big endian ..
int endian(void)
{
short magic, test;
char * ptr;
magic = 0xABCD; /* endianess magic number */
ptr = (char *) &magic;
test = (ptr[1]<<8) + (ptr[0]&0xFF); /* build value byte by byte
*/
return (magic == test); /* if the same is little
endian */
}
But, maybe, this is not compiler indipendent...
Daniele.
There are generally macros that are defined depending on the endianess
(whether provided by the vendor or by a preconfiguration step).
>
> int endian(void)
> {
> short magic, test;
> char * ptr;
>
> magic = 0xABCD; /* endianess magic number */
> ptr = (char *) &magic;
> test = (ptr[1]<<8) + (ptr[0]&0xFF); /* build value byte by byte
> */
> return (magic == test); /* if the same is little
> endian */
> }
>
> But, maybe, this is not compiler indipendent...
That doesn't account for all format but it is fairly portable.
--
Michael
> > u.m1.c = 'a';
> > putchar(u.m2.c);
> > is conformant...
Yes. Supposedly, in some circles, something along these lines
was used to simulate polymorphism. The "initial sequence" was
defined by a macro, and included a type tag, and the union was a
polymorphic object---whose type could even be changed
dynamically. (The solution I've usually seen was:
struct h { int tag ; /*...*/ } ;
struct s1 { struct h head; ... } ;
struct s2 { struct h head; ... } ;
then pass h* around, casting them to s1* or s2* as needed.)
But since you can't put incomplete types in a union, it has this
information.
The issue is more than a little complicated, because on one
hand, we want cleanly written code to work, without particular
precautions, and on the other, we want to allow a maximum of
optimizing. In the end: if you're using a union to hold
different types at different times (as guaranteed by the
standard), it will in practice work if the union is visible to
the compiler where ever the data are accessed. And for type
punning, you'll really have to check what you're doing for each
compiler (and maybe pass special flags or turn off some
optimizations).
[...]
> Still, I wish we could at least agree that a char is 8 bits, a
> short is 16, a long 32, etc.
Except that they aren't, and can't be on some machines. (For
that matter, long is more often 64 bits than 32.)
_THAT'S_ what I'm talking 'bout.
Jack
Not true -- in embedded software in microcontrollers (and there's lots
more of them than Unix machines), a long is almost universally 32 bits.
But that's neither here nor there. We need a set of types that _CAN_ be
implemented the same way on all machines. Otherwise all the union tricks
that we've talked about, don't work. And I don't care, either, if the
keywords are "char", "int", and "long." In fact, I much prefer "byte",
"word", and "longword." Perhaps Pete's stdint.h is the answer.
It shouldn't take much effort to write a header file that defines these
words in a way that's implementation dependent. Then, #include that
header, and you can encapsulate all the machine dependencies into one
short file.
Jack
Maybe not, but it's a great idea. I routinely use little functions or
files of consts to set the values of oft-used constants. e.g.,
const double pi = 4.0*atan(1.0);
const double root2 = sqrt(2.0);
..
A small function to define endian-ness would fit right in there.
Jack
..
>
> Daniele.
> Pete Becker wrote:
>> On 2009-01-22 10:37:28 -0500, Jack Crenshaw <jcr...@earthlink.net> said:
>>
>>>
>>> Still, I wish we could at least agree that a char is 8 bits, a short is
>>> 16, a long 32, etc. I'd lots rather know, up front, that I need to do
>>> a multi-file global replace, than to find out the hard way that
>>> someone's changed the rules on me.
>>>
>>
>> They're all at least that large, so if you write code that doesn't
>> exceed those limits it will be portable.
>>
>> If you need exact sizes, there's int8_t, int16_t, etc. from <stdint.h>
>> (coming soon to a C++ standard near you).
>
> _THAT'S_ what I'm talking 'bout.
I forgot to mention: it's already in C99.
And if the compiler doesn't offer, then the similar Boost header might work.
Cheers (& to OP, hth. (that's not to Pete because Pete already knew that))
- Alf
Such function is next to useless if it is not deductible at compile
time. At runtime, the noth* and hton* are more secure to handle
endianess convertion.
Endianess awareness is useful if you want to map a binary layout with a
structure; especially with bit-fields. An example is the layout of a IP
header.
--
Michael
Hi..like always I need to go a step forward...
I have a char* = {0x11, 0x8E, 0xCD, 0x8D} and I have to transform it
into a float value 294571405.
I've read some old posts but with no luck!
The following post (http://groups.google.it/group/comp.lang.c++/
browse_frm/thread/22a97dda79ea08fb/6e4af8cd9c7b0db3) is exatcly what I
need...it gives some solutions that seems to be not portable..
Any suggestions?
Tnx,
Daniele.