473,396 Members | 1,599 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Int to char[4]

Hello, just wondering how I would assign a char array of four elements
to the four bytes used in an int. As of right now my code is:
cNameSize = (char)((void)NameSize);
cFileSize = (char)((void)FileSize);
Where NameSize and FileSize are the integers, and cNameSize and
cFileSize are 4 element arrays. This doesn't work.

Jan 28 '07 #1
43 3828
Th************@gmail.com wrote:
Hello, just wondering how I would assign a char array of four elements
to the four bytes used in an int. As of right now my code is:
cNameSize = (char)((void)NameSize);
cFileSize = (char)((void)FileSize);
Where NameSize and FileSize are the integers, and cNameSize and
cFileSize are 4 element arrays. This doesn't work.
Neither of the above are valid. Your first issue is you can't
assign arrays at all. The easiest way is just to use memcpy:

int NameSize;
char cNameSize[4];

memcpy(cNameSize, &NameSize, 4);
Jan 28 '07 #2
In article <11*********************@j27g2000cwj.googlegroups. com>,
Th************@gmail.com says...
Hello, just wondering how I would assign a char array of four elements
to the four bytes used in an int. As of right now my code is:
cNameSize = (char)((void)NameSize);
cFileSize = (char)((void)FileSize);
Where NameSize and FileSize are the integers, and cNameSize and
cFileSize are 4 element arrays. This doesn't work.
You can't do anything entirely portably. About as good as it gets is:

union type_pun {
int i;
char c[sizeof(int)];
};

Officially, it gives undefined behavior, but with a typical compiler you
can write an int into i, and then access its individual bytes via c.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jan 28 '07 #3
Jerry Coffin wrote:
In article <11*********************@j27g2000cwj.googlegroups. com>,
Th************@gmail.com says...
>>Hello, just wondering how I would assign a char array of four elements
to the four bytes used in an int. As of right now my code is:
cNameSize = (char)((void)NameSize);
cFileSize = (char)((void)FileSize);
Where NameSize and FileSize are the integers, and cNameSize and
cFileSize are 4 element arrays. This doesn't work.


You can't do anything entirely portably. About as good as it gets is:

union type_pun {
int i;
char c[sizeof(int)];
};

Officially, it gives undefined behavior, but with a typical compiler you
can write an int into i, and then access its individual bytes via c.
Assuming you aren't concerned with the byte order.

--
Ian Collins.
Jan 28 '07 #4
In article <52*************@mid.individual.net>, ia******@hotmail.com
says...
Jerry Coffin wrote:
[ ... ]
union type_pun {
int i;
char c[sizeof(int)];
};

Officially, it gives undefined behavior, but with a typical compiler you
can write an int into i, and then access its individual bytes via c.
Assuming you aren't concerned with the byte order.
....or, perhaps more accurately, assuming you're ready to deal with byte
order on your own. If you want to avoid that, you can do something like:

for (int i=0; i<4; i++)
byte[i] = (integer >i * 8) & 0xff;

If you don't want to assume an 8-bit char, you can base the mask and
shift on std::numeric_limits<char>::digits (and possibly radix, if
you're concerned with the possibility of non-binary represenations).

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jan 28 '07 #5
Jerry Coffin wrote:
In article <11*********************@j27g2000cwj.googlegroups. com>,
Th************@gmail.com says...
Hello, just wondering how I would assign a char array of four
elements to the four bytes used in an int. As of right now my code
is: cNameSize = (char)((void)NameSize);
cFileSize = (char)((void)FileSize);
Where NameSize and FileSize are the integers, and cNameSize and
cFileSize are 4 element arrays. This doesn't work.

You can't do anything entirely portably. About as good as it gets is:

union type_pun {
int i;
char c[sizeof(int)];
};

Officially, it gives undefined behavior, but with a typical compiler
you can write an int into i, and then access its individual bytes via
c.

You don't need to go through all that union stuff to do that. Perfectly
safe and portable is:

int i = 123;
unsigned char* p;

p = (char*) &i;

Brian

Jan 28 '07 #6
In article <52*************@mid.individual.net>, de***********@yahoo.com
says...

[ ... ]
Perfectly safe and portable is:

int i = 123;
unsigned char* p;

p = (char*) &i;
Section 5.2.10/7 of the C++ standard seems to disagree.

Don't get me wrong: none of the other methods produces a specified
result either -- but I see little evidence that this one is any safer or
more portable than any of the others. Using your example, I could
perfectly reasonably have *p == 0 or *p == 123, depending on whether the
machine was little endian or big endian. Of course, with the possibility
of padding bits and such, there could be other values as well, but both
of those are _extremely_ common.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jan 28 '07 #7
Jerry Coffin wrote:
In article <52*************@mid.individual.net>, de***********@yahoo.com
says...

[ ... ]
>Perfectly safe and portable is:

int i = 123;
unsigned char* p;

p = (char*) &i;

Section 5.2.10/7 of the C++ standard seems to disagree.
Well, of course the result is unspecified, but with the enum trick, it's
undefined.
Don't get me wrong: none of the other methods produces a specified
result either -- but I see little evidence that this one is any safer or
more portable than any of the others.
I agree. However, I'd still not go through the union. For one, the cast is
simpler, and it's the tool that was made for the job. Unions are not meant
to be used like that. I mean, you may be able to use a brick to hammer a
nail into a wall, but a hammer just seems to be a more "natural" choice.

Jan 29 '07 #8
In article <ep*************@news.t-online.com>, ra******@t-online.de
says...

[ ... ]
I agree. However, I'd still not go through the union. For one, the cast is
simpler, and it's the tool that was made for the job. Unions are not meant
to be used like that. I mean, you may be able to use a brick to hammer a
nail into a wall, but a hammer just seems to be a more "natural" choice.
In this case, the correct metaphor doesn't seem to be comparing a hammer
to a brick, but comaparing a chunk of reddish granite to a chunk of grey
granite, both roughly the same size and shape.

If he'd used a reinterpret_cast instead of a C-style cast, you _might_
have a point, but even then (IMO) we're just talking about a
specifically designated chunk of granite, still not really a hammer.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jan 29 '07 #9


On 28 Jan., 21:41, Jerry Coffin <jcof...@taeus.comwrote:
In article <524e25F1mn9c...@mid.individual.net>, ian-n...@hotmail.com
says...
Jerry Coffin wrote:[ ... ]
union type_pun {
int i;
char c[sizeof(int)];
};
Officially, it gives undefined behavior, but with a typical compiler you
can write an int into i, and then access its individual bytes via c.
Assuming you aren't concerned with the byte order
....or, perhaps more accurately, assuming you're ready to deal with byte
order on your own. If you want to avoid that, you can do something like:

for (int i=0; i<4; i++)
byte[i] = (integer >i * 8) & 0xff;
This probably is not what is wanted: shifting ints is implementation
defined and should normally be avoided. I would either use the union
trick (have never seen it not work) or use an unsigned int.

/Peter
>
If you don't want to assume an 8-bit char, you can base the mask and
shift on std::numeric_limits<char>::digits (and possibly radix, if
you're concerned with the possibility of non-binary represenations).
Jan 29 '07 #10
Default User wrote:
>
You don't need to go through all that union stuff to do that. Perfectly
safe and portable is:

int i = 123;
unsigned char* p;

p = (char*) &i;
You want to use unsigned char* in the cast to match the
type of p
Jan 29 '07 #11
In article <11**********************@h3g2000cwc.googlegroups. com>,
pe***************@gmail.com says...

[ ... ]
This probably is not what is wanted: shifting ints is implementation
defined and should normally be avoided.
Specifically, right-shifting an int. I wasn't thinking of that when I
posted, but you're absolutely right.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jan 29 '07 #12
Shifting an unsigned int into an unsigned char is probably the most
portable because in that case, both the bit order and byte order do
not matter. The union version doesn't work because the standard only
allows you to inspect the common initial sequence of two structs.
However, the cast version works.

The problem with the C-style cast is that it's interpreted as a
reinterpret_cast and it's not required that you're able to access the
object after a reinterpret_cast. The standard mentions some places
where a (static) cast to void * then to char * is OK. As long as you
don't try to interpret a character array as an int (due to alignment
issues), and use memcpy instead, there won't be any trouble. However,
both the byte and bit orders are unspecified, and there are no
guarantees on anything except that copying a sequence out of an
integer, then back into (a possibly different) integer, will make that
integer retain the same value. The integer could have padding and trap
bits which may throw off contraints of the program if given arbitrary
values. I'd stick with shifts.

There's also a caveat with using shifts with an unsigned int, copying
to chars. char could be signed, so doing this:

unsigned int x = 0xFF00;
char c = char(x >CHAR_BIT); // equivalent to char c = char(0xFF); if
CHAR_BIT is 8.

isn't guaranteed to produce anything specific even if CHAR_BIT is 8.
The result is implementation-defined, since 0xFF would be larger than
c can represent. There's also the fact that, even when the char has 8
bits, it doesn't have to represent -128, so it can do whatever it
wants when you try to do anything but copy that value to another char.
(Unlike signed char, it has to be valid to store that representation
because all POD objects are guaranteed to be able to be readable as a
series of chars or unsigned chars, and all bits of any char type have
to participate in value representation.)

Jan 29 '07 #13
<Th************@gmail.comwrote in message
news:11*********************@j27g2000cwj.googlegro ups.com...
Hello, just wondering how I would assign a char array of four elements
to the four bytes used in an int. As of right now my code is:
cNameSize = (char)((void)NameSize);
cFileSize = (char)((void)FileSize);
Where NameSize and FileSize are the integers, and cNameSize and
cFileSize are 4 element arrays. This doesn't work.
I've done it a few different ways depending on why I'm doing it and what
makes it most obvious to some future reader of my program what I'm doing and
why.

#include <iostream>
#include <string>

int main ()
{
// Method 1
int p1 = 1234;
char n1[4];
*(reinterpret_cast<int*>( n1 )) = p1;

// Method 2
union
{
int p2;
char n2[4];
};
p2 = 1234;

// Method 3
int p3 = 1234;
char n3[4];
for ( int i = 0; i < sizeof p3; ++i )
n3[i] = reinterpret_cast<char*>( &p3 )[i];

// Method 4 - Don't bother converting yet.
int p4 = 1234;

// Just output to show they do the same thing
for ( int i = 0; i < 4; ++i )
std::cout << static_cast<unsigned int>( n1[i] ) << " ";
std::cout << "\n";

for ( int i = 0; i < 4; ++i )
std::cout << static_cast<unsigned int>( n2[i] ) << " ";
std::cout << "\n";

for ( int i = 0; i < 4; ++i )
std::cout << static_cast<unsigned int>( n3[i] ) << " ";
std::cout << "\n";

for ( int i = 0; i < 4; ++i )
std::cout << static_cast<unsigned int>(reinterpret_cast<char*>(
&p4 )[i]) << " ";
std::cout << "\n";

std::cin.get();
}

I've also written functions to do this, methods, used memcpy, etc...

It is actually very easy to get to each byte of anything.
Jan 29 '07 #14
Jim Langston wrote:
<Th************@gmail.comwrote in message
news:11*********************@j27g2000cwj.googlegro ups.com...
>Hello, just wondering how I would assign a char array of four elements
to the four bytes used in an int. As of right now my code is:
cNameSize = (char)((void)NameSize);
cFileSize = (char)((void)FileSize);
Where NameSize and FileSize are the integers, and cNameSize and
cFileSize are 4 element arrays. This doesn't work.

I've done it a few different ways depending on why I'm doing it and what
makes it most obvious to some future reader of my program what I'm doing
and why.

#include <iostream>
#include <string>

int main ()
{
// Method 1
int p1 = 1234;
char n1[4];
*(reinterpret_cast<int*>( n1 )) = p1;
[snip]

This one is interesting. Are you sure, n1 satisfies the alignment
requirements for int? (And I wondern what happens if it is not. Will the
reinterpret_cast modify the pointer so that one gets a valid int* to an
overlapping but different memory region, will the assignment fail, or will
we see the proverbial nasal daemons?)
Best

Kai-Uwe Bux
Jan 29 '07 #15
"Kai-Uwe Bux" <jk********@gmx.netwrote in message
news:ep*********@murdoch.acc.Virginia.EDU...
Jim Langston wrote:
><Th************@gmail.comwrote in message
news:11*********************@j27g2000cwj.googlegr oups.com...
>>Hello, just wondering how I would assign a char array of four elements
to the four bytes used in an int. As of right now my code is:
cNameSize = (char)((void)NameSize);
cFileSize = (char)((void)FileSize);
Where NameSize and FileSize are the integers, and cNameSize and
cFileSize are 4 element arrays. This doesn't work.

I've done it a few different ways depending on why I'm doing it and what
makes it most obvious to some future reader of my program what I'm doing
and why.

#include <iostream>
#include <string>

int main ()
{
// Method 1
int p1 = 1234;
char n1[4];
*(reinterpret_cast<int*>( n1 )) = p1;
[snip]

This one is interesting. Are you sure, n1 satisfies the alignment
requirements for int? (And I wondern what happens if it is not. Will the
reinterpret_cast modify the pointer so that one gets a valid int* to an
overlapping but different memory region, will the assignment fail, or will
we see the proverbial nasal daemons?)
I've actually contemplated that, which is why I am hesitant to use this
method in code that won't stay on one OS. The main reason I throw ints into
char arrays, and vice versa, is moving data from/to socket streams which are
char buffers. I know the next 4 bytes are a binary integer and want to get
it into an interger variable.

It's wored for me when I've used it on Windows XP in MS C++ .net 2003 but I
would think it may not work on some computers that have to have ints aligned
or won't work at all.

It's actually the one I tend to like the most, but have the most difficulty
deciding if it's good code or not. On a windows machine I can only envision
it being as fast as, or faster, than moving char by char (it's either going
to do it in one move, two or four). Not that speed really matters.

The uniion I really don't like, but is probably the concicest.
Jan 29 '07 #16
Ron Natalie wrote:
Default User wrote:

You don't need to go through all that union stuff to do that.
Perfectly safe and portable is:

int i = 123;
unsigned char* p;

p = (char*) &i;
You want to use unsigned char* in the cast to match the
type of p
Yeah, oops. Careless of me.

Brian
Jan 29 '07 #17
On 1/28/07 10:39 PM, in article ep*********@murdoch.acc.Virginia.EDU,
"Kai-Uwe Bux" <jk********@gmx.netwrote:
Jim Langston wrote:
>#include <iostream>
#include <string>

int main ()
{
// Method 1
int p1 = 1234;
char n1[4];
*(reinterpret_cast<int*>( n1 )) = p1;
[snip]

This one is interesting. Are you sure, n1 satisfies the alignment
requirements for int? (And I wondern what happens if it is not. Will the
reinterpret_cast modify the pointer so that one gets a valid int* to an
overlapping but different memory region, will the assignment fail, or will
we see the proverbial nasal daemons?)
No, there is no problem with alignment in the above code. However there are
plenty of other reasons to find faults with this program: the double storage
is inefficient while the use of reinterpret_cast is inelegant, to use as
charitable a description as possible).

However unsightly this code may be, it will not blow up when run. Because
the four chars of storage for the int were allocated by a single array
object (n1), the storage will be aligned according the most stringent
alignment requirements of any four-byte sized type (including a four-byte
int type).

In fact a C++ program can always be certain that as long as a character
array is equal to (or larger than) the sizeof() a POD type, then the program
will be able to place of an object of that type into that character array
safely.

Greg

Jan 29 '07 #18
Jerry Coffin wrote:
In article <52*************@mid.individual.net>,
de***********@yahoo.com says...

[ ... ]
Perfectly safe and portable is:

int i = 123;
unsigned char* p;

p = (char*) &i;

Section 5.2.10/7 of the C++ standard seems to disagree.
I don't have a copy of the standard at home, but I don't believe
there's anything undefined or otherwise unsafe about this. The layout
of the int is of course not specified by the standard, but any object
can be examined as a sequence of bytes safely.
Don't get me wrong: none of the other methods produces a specified
result either -- but I see little evidence that this one is any safer
or more portable than any of the others. Using your example, I could
perfectly reasonably have *p == 0 or *p == 123, depending on whether
the machine was little endian or big endian. Of course, with the
possibility of padding bits and such, there could be other values as
well, but both of those are extremely common.
So? That's no different from what you have, except that the cast to one
of the char* types is specified to be safe. It avoids a lot of
unnecessary business in the union. If all you want to do is examine the
byte layout of an object, casting to unsigned char* is the way to go
(don't make my error that Ron pointed out, of course).

Brian
Jan 29 '07 #19
Greg Herlihy wrote:
On 1/28/07 10:39 PM, in article ep*********@murdoch.acc.Virginia.EDU,
"Kai-Uwe Bux" <jk********@gmx.netwrote:
>Jim Langston wrote:
>>#include <iostream>
#include <string>

int main ()
{
// Method 1
int p1 = 1234;
char n1[4];
*(reinterpret_cast<int*>( n1 )) = p1;
[snip]

This one is interesting. Are you sure, n1 satisfies the alignment
requirements for int? (And I wondern what happens if it is not. Will the
reinterpret_cast modify the pointer so that one gets a valid int* to an
overlapping but different memory region, will the assignment fail, or
will we see the proverbial nasal daemons?)

No, there is no problem with alignment in the above code. However there
are plenty of other reasons to find faults with this program: the double
storage is inefficient while the use of reinterpret_cast is inelegant, to
use as charitable a description as possible).

However unsightly this code may be, it will not blow up when run. Because
the four chars of storage for the int were allocated by a single array
object (n1), the storage will be aligned according the most stringent
alignment requirements of any four-byte sized type (including a four-byte
int type).

In fact a C++ program can always be certain that as long as a character
array is equal to (or larger than) the sizeof() a POD type, then the
program will be able to place of an object of that type into that
character array safely.
Before I posted, I hit the standard to find out (because I vaguely
remembered something like this). However, all I was able to confirm is that
allocation functions return pointer suitably aligned for any size that fits
in there [5.3.4/10]. I did not find a corresponding guarantee for character
arrays that are not dynamically allocated. Could you point me to the clause
that says so.
Thanks

Kai-Uwe Bux
Jan 29 '07 #20
Na********@gmail.com wrote:
>
The union version doesn't work because the standard only
allows you to inspect the common initial sequence of two structs.
What does it mean?

union X
{
int i;
char c[sizeof(int)];
};

X tmp;

1. "tmp" is aligned for "X::i" X::i (has offset zero)
2. "X::i" and "X::c" is started from the same memory adr
3. type "int" has "sizeof(int)" chars placed without holes - one by one

Why not?

--
Maksim A Polyanin
Jan 29 '07 #21
Kai-Uwe Bux wrote:
>
Jim Langston wrote:
> // Method 1
int p1 = 1234;
char n1[4];
*(reinterpret_cast<int*>( n1 )) = p1;

This one is interesting. Are you sure, n1 satisfies the alignment
requirements for int?
I think, you are right, we can get wrong alignment here. It is better to do
like this:

int p1 = 1234;

//to force buf align and size
int p2 = 0;
char *n1=reinterpret_cast<char*>(&p2);

*(reinterpret_cast<int*>( n1 )) = p1;
n1[0..3]=0;

//is not aligned now
char buf[4];
n1=buf;

//can be error
*(reinterpret_cast<int*>( n1 )) = p1;
n1[0..3]=0;
(And I wondern what happens if it is not.
Memory access violation can occur on some targets.

--
Maksim A Polyanin
Jan 29 '07 #22
Jerry Coffin wrote:
In article <ep*************@news.t-online.com>, ra******@t-online.de
says...

[ ... ]
>I agree. However, I'd still not go through the union. For one, the cast
is simpler, and it's the tool that was made for the job. Unions are not
meant to be used like that. I mean, you may be able to use a brick to
hammer a nail into a wall, but a hammer just seems to be a more "natural"
choice.

In this case, the correct metaphor doesn't seem to be comparing a hammer
to a brick, but comaparing a chunk of reddish granite to a chunk of grey
granite, both roughly the same size and shape.

If he'd used a reinterpret_cast instead of a C-style cast, you _might_
have a point, but even then (IMO) we're just talking about a
specifically designated chunk of granite, still not really a hammer.
Ok, maybe the metaphor wasn't that good, so let's not discuss if a
reinterpret_cast is a hammer or a chunk of granite. What matters to me is
that reinterpret_cast is the tool actually designed for the task, and a
union is not. When having a choice, I stick with using the language as it
was intended, so I'd always choose the reinterpret_cast.

Jan 29 '07 #23
On Jan 29, 9:35 pm, Greg Herlihy <gre...@pacbell.netwrote:
Jim Langston wrote:
// Method 1
int p1 = 1234;
char n1[4];
*(reinterpret_cast<int*>( n1 )) = p1;
[snip]
No, there is no problem with alignment in the above code.
Actually there is. The char array might not be correctly aligned
for an int.
However unsightly this code may be, it will not blow up when run. Because
the four chars of storage for the int were allocated by a single array
object (n1), the storage will be aligned according the most stringent
alignment requirements of any four-byte sized type (including a four-byte
int type).
Completely untrue.
In fact a C++ program can always be certain that as long as a character
array is equal to (or larger than) the sizeof() a POD type, then the program
will be able to place of an object of that type into that character array
safely.
You can place the object there by memcpy'ing it. But you may not
be able to create a pointer to that object type, and point it to the
char array.

Jan 29 '07 #24
In article <52*************@mid.individual.net>, de***********@yahoo.com
says...

[ ... ]
I don't have a copy of the standard at home, but I don't believe
there's anything undefined or otherwise unsafe about this.
Sorry, but on that point you're simply mistaken.
The layout
of the int is of course not specified by the standard, but any object
can be examined as a sequence of bytes safely.
In C99 you'd be right -- and someday, C++ might follow suit -- but as
far as I can see, they're both undefined behavior at least for now.

[ ... ]
So? That's no different from what you have, except that the cast to one
of the char* types is specified to be safe. It avoids a lot of
unnecessary business in the union. If all you want to do is examine the
byte layout of an object, casting to unsigned char* is the way to go
(don't make my error that Ron pointed out, of course).
See above -- in C99, it's true that the cast to pointer to a char type
gives defined (if unspecified) results. I don't see such requirement in
the C++ standard though.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jan 30 '07 #25
In article <ep**********@aioe.org>, gr******@yandex.ru says...
Na********@gmail.com wrote:

The union version doesn't work because the standard only
allows you to inspect the common initial sequence of two structs.
What does it mean?

union X
{
int i;
char c[sizeof(int)];
};

X tmp;

1. "tmp" is aligned for "X::i" X::i (has offset zero)
2. "X::i" and "X::c" is started from the same memory adr
3. type "int" has "sizeof(int)" chars placed without holes - one by one

Why not?
C89 specifically required that only the most recently written member of
a union could be read, and violating this resulted in implementation-
defined behavior ("With on exception, if a member of a union object is
accessed after a value has been stored in a different member of the
object, the behavior is implementation-defined." $6.3.2.3). Interpreted
literally, that means the following code gives implementation defined
behavior:

union X {
int i;
float j;
};

int main() {
union X x;
int a;

x.i = 1;
x.j = 1.0;
x.i = 0;
a = x.i;
return 0;
}

Even though x.i was the most recently stored member when x.i is
accessed, the access to x.i does take place "after a value has been
stord in a different member of the object."

In both C++ and C99, this (explicit) requirement seems to have
disappeared (though both still contain language about a "special" rule
dispensing with the requirement on the common initial sequence, sort of
implying that the disappearance of the rule may not have been entirely
intentional). It's open to argument that the undefined behavior still
exists, simply because neither explicitly defines what happens when you
read from a different member than was last written.

OTOH, the standard explicitly requires that the storage for the objects
in the union overlap, and that the union be aligned so that a pointer to
the beginning of the union can be used to dereference any member (and
vice versa) -- and this is true in both C and C++. So the alignment is
guaranteed to work, but the type-pun (arguably) might not.

A reinterpret_cast (even if it looks like a C-style cast) usually has a
problem with alignment: even though everybody "knows" that char has no
alignment requirements, the standard doesn't seem to directly guarantee
it (then again, the required similarity between pointer to char and
pointer to void could be interpreted as such). If you put the int into
dynamically allocated memory, it guarantees that its first byte is
aligned to be accessed as a char, but the remainder still might not be.

The shift and mask method works for essentially any data, but it's
clumsy (at best) to make it entirely portable. You need to convert the
int to unsigned before you do right shifting, and you need to use
CHAR_BIT to figure out how many bits there are in a byte, and use that
as the basis for your mask, etc. Even with all that, you have to live
with the fact that the int could contain some padding bits, so you could
have some number of bits in the byte-by-byte representation that are
zero for all possible inputs.

AFAIK, the lack of portability of either the cast or the union method is
purely theoretical. None of the methods is what I'd call beautiful by
any means, though the (portable) version of the shift/mask method is
undoubtedly the longest, probably the ugliest, and the most likely to
involve extra instructions. Between the cast and the union, it's close
to a toss-up: neither guarantees portability (in C+++; the cast is semi-
portable in C99), but both are for all practical purposes. Both strike
me as ugly, though I think the cast is somewhat more so. The cast by
itself is fairly ugly, but when you add in the requirement to take the
address of the int, the cast that to pointer to char, then dereference
the resulting pointer, the whole is really pretty hideous (and the fact
that it's basically the only way to use a reinterpret_cast doesn't make
it any less hideous, IMO).

If possible, the real answer is to avoid all of the above, and simply
find an entirely different way to solve the problem.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jan 30 '07 #26
Jerry Coffin wrote:
In article <52*************@mid.individual.net>, de***********@yahoo.com
says...

[ ... ]
>I don't have a copy of the standard at home, but I don't believe
there's anything undefined or otherwise unsafe about this.

Sorry, but on that point you're simply mistaken.
>The layout
of the int is of course not specified by the standard, but any object
can be examined as a sequence of bytes safely.

In C99 you'd be right -- and someday, C++ might follow suit -- but as
far as I can see, they're both undefined behavior at least for now.
Quote from the standard (§3.9):

"For any complete POD object type T, whether or not the object holds a valid
value of type T, the underlying bytes (1.7) making up the object can be
copied into an array of char or unsigned char."

and:

"The object representation of an object of type T is the sequence of N
unsigned char objects taken up by the object of type T, where N equals
sizeof(T)."

Jan 30 '07 #27
Jerry Coffin wrote:

A reinterpret_cast (even if it looks like a C-style cast) usually has
a problem with alignment: even though everybody "knows" that char has
no alignment requirements, the standard doesn't seem to directly
guarantee it (then again, the required similarity between pointer to
char and pointer to void could be interpreted as such). If you put
the int into dynamically allocated memory, it guarantees that its
first byte is aligned to be accessed as a char, but the remainder
still might not be.
You are simply not correct about this. The standard does guarantee that
POD types can be accessed as byte buffers. Not only that, if there were
some sort of alignment concern, your union would have the same problem.

Brian
Jan 30 '07 #28
In article <ep*************@news.t-online.com>, ra******@t-online.de
says...

[ ... ]
In C99 you'd be right -- and someday, C++ might follow suit -- but as
far as I can see, they're both undefined behavior at least for now.
Quote from the standard (§3.9):

"For any complete POD object type T, whether or not the object holds a valid
value of type T, the underlying bytes (1.7) making up the object can be
copied into an array of char or unsigned char."
Copied into an array of char is one thing -- but using the cast is NOT
copying it anywhere, it's leaving it where it is, and attempting to
_treat_ it as an array of char.
and:

"The object representation of an object of type T is the sequence of N
unsigned char objects taken up by the object of type T, where N equals
sizeof(T)."
If this has any relevance, I'm missing it.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jan 31 '07 #29
In article <52*************@mid.individual.net>, de***********@yahoo.com
says...
Jerry Coffin wrote:

A reinterpret_cast (even if it looks like a C-style cast) usually has
a problem with alignment: even though everybody "knows" that char has
no alignment requirements, the standard doesn't seem to directly
guarantee it (then again, the required similarity between pointer to
char and pointer to void could be interpreted as such). If you put
the int into dynamically allocated memory, it guarantees that its
first byte is aligned to be accessed as a char, but the remainder
still might not be.

You are simply not correct about this. The standard does guarantee that
POD types can be accessed as byte buffers.
Where does it guarantee that? The closest I see is at 3.9/2, and that
seems to fall a bit short of what you're claiming.
Not only that, if there were
some sort of alignment concern, your union would have the same problem.
No, it would not. The standard specifically requires that a union be
aligned so that each member is accessible and the addresses of all those
members are equal to each other and to the addess of the union.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jan 31 '07 #30
Jerry Coffin wrote:
In article <ep*************@news.t-online.com>, ra******@t-online.de
says...

[ ... ]
In C99 you'd be right -- and someday, C++ might follow suit -- but as
far as I can see, they're both undefined behavior at least for now.

Quote from the standard (§3.9):

"For any complete POD object type T, whether or not the object holds a
valid value of type T, the underlying bytes (1.7) making up the object
can be copied into an array of char or unsigned char."

Copied into an array of char is one thing -- but using the cast is NOT
copying it anywhere, it's leaving it where it is, and attempting to
_treat_ it as an array of char.
How do you copy it to an array of char without treating it as one?
>and:

"The object representation of an object of type T is the sequence of N
unsigned char objects taken up by the object of type T, where N equals
sizeof(T)."

If this has any relevance, I'm missing it.
It says that the object representation is an array of unsigned char. If it
is one, you can treat it as one.

Jan 31 '07 #31
In article <ep*************@news.t-online.com>, ra******@t-online.de
says...

[ ... ]
How do you copy it to an array of char without treating it as one?
char *dest = new malloc(sizeof(int));

*(int *)dest = src_int;

for (size_t i=0; i<sizeof(int); i++)
use(dest[i]);

Here you're copying it as an int. malloc returns storage aligned for any
possible type, so we've eliminated that problem. We copy the int as an
int, into an array of char, so we're doing the copying without treating
it as an array of char. Then, only after we've transferred the bits to
the array of char, do we look at the char's for what they really are.

I'll repeat though: I think this is all mostly nonsense. The mere fact
that the standard doesn't quite guarantee what most people think it does
is no real reason to get stupid about writing more complex code than
necessary for the portability you actually need. Even if you're sure I'm
wrong about what the standard requires, it's not going to change much:
either the compilers you care about will accept your code, or else they
won't. While it's nice to think of the standard as an absolute, we all
know that in real life, it's little more than a general guideline. We
all now most compilers don't conform even with requirements we can all
agree are present.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jan 31 '07 #32
Jerry Coffin wrote:
In both C++ and C99, this (explicit) requirement seems to have
disappeared (though both still contain language about a "special" rule
dispensing with the requirement on the common initial sequence, sort of
implying that the disappearance of the rule may not have been entirely
intentional). It's open to argument that the undefined behavior still
exists, simply because neither explicitly defines what happens when you
read from a different member than was last written.
It still says that only the value of one of the members can be stored in it
at any time. I don't see any rule (other than the exception of the common
initial sequence) that says you can read any other member than the one
currently stored.
A reinterpret_cast (even if it looks like a C-style cast) usually has a
problem with alignment: even though everybody "knows" that char has no
alignment requirements, the standard doesn't seem to directly guarantee
it (then again, the required similarity between pointer to char and
pointer to void could be interpreted as such).
It is guaranteed, simply due to the fact that sizeof(char) is always 1. If
char had any special alignment requirements, you couldn't create arrays of
char, and that would violate the standard.
AFAIK, the lack of portability of either the cast or the union method is
purely theoretical. None of the methods is what I'd call beautiful by
any means, though the (portable) version of the shift/mask method is
undoubtedly the longest, probably the ugliest, and the most likely to
involve extra instructions.
IMHO, the best way to deal with it is to put the required conversions into
their own functions and adapt those to target platforms that need that.
There is no really portable way of doing binary I/O (which I assume to be
the actual reason for the cast).

Jan 31 '07 #33
Jerry Coffin wrote:
In article <ep*************@news.t-online.com>, ra******@t-online.de
says...

[ ... ]
>How do you copy it to an array of char without treating it as one?

char *dest = new malloc(sizeof(int));

*(int *)dest = src_int;
[..]

This is fine. The alignment of dynamically allocated block is
different from one allocated automatically. The OP asked about
an automatic array of char, IIRC. That's why the whole alignment
discussion was started. So, to reiterate, this

char *dest = new malloc(sizeof(int));
*(int*)dest = 42;

is fine, however, this

char dest[sizeof(int)];
*(int*)dest = 42;

is NOT.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jan 31 '07 #34
In article <ep**********@news.datemas.de>, v.********@comAcast.net
says...

[ ... ]
This is fine. The alignment of dynamically allocated block is
different from one allocated automatically. The OP asked about
an automatic array of char, IIRC. That's why the whole alignment
discussion was started. So, to reiterate, this

char *dest = new malloc(sizeof(int));
*(int*)dest = 42;

is fine,
....other than that minor detail that you copied my typo of "new
malloc" -- obviously you need new or malloc, but not both. :-)

--
Later,
Jerry.

The universe is a figment of its own imagination.
Feb 1 '07 #35
In article <ep*************@news.t-online.com>, ra******@t-online.de
says...

[ ... ]
It is guaranteed, simply due to the fact that sizeof(char) is always 1. If
char had any special alignment requirements, you couldn't create arrays of
char, and that would violate the standard.
You're assuming that all machines are quite a bit like you're accustomed
to. That's not necessarily the case. Consider a machine with two
entirely separate memories, one that's byte-addressable, but relatively
small, while the other is only word addressable, but larger. When you
ask for char's, it's allocated from the first memory, but when you ask
for int's, it's allocated from the second. If you want to copy from the
second to the first, you can do that -- but only by reading an entire
word, not individual bytes.

Many DSPs are more or less like this: they start as more or less Harvard
architectures, with separate memories (including separate busses) for
data and instructions. For the sake of speed, however, some instructions
can use the instruction memory as a secondary data memory -- but often
with restrictions. When/if you work with data that doesn't fit those
restrictions, it needs to be allocated in the main data memory...

[ ... ]
IMHO, the best way to deal with it is to put the required conversions into
their own functions and adapt those to target platforms that need that.
There is no really portable way of doing binary I/O (which I assume to be
the actual reason for the cast).
Assuming that's really the case (and I'm not disputing it, just
admitting that I'm not sure) I agree.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Feb 1 '07 #36
Jerry Coffin wrote:
In article <ep*************@news.t-online.com>, ra******@t-online.de
says...

[ ... ]
>It is guaranteed, simply due to the fact that sizeof(char) is always 1.
If char had any special alignment requirements, you couldn't create
arrays of char, and that would violate the standard.

You're assuming that all machines are quite a bit like you're accustomed
to. That's not necessarily the case. Consider a machine with two
entirely separate memories, one that's byte-addressable, but relatively
small, while the other is only word addressable, but larger. When you
ask for char's, it's allocated from the first memory, but when you ask
for int's, it's allocated from the second. If you want to copy from the
second to the first, you can do that -- but only by reading an entire
word, not individual bytes.

Many DSPs are more or less like this: they start as more or less Harvard
architectures, with separate memories (including separate busses) for
data and instructions. For the sake of speed, however, some instructions
can use the instruction memory as a secondary data memory -- but often
with restrictions. When/if you work with data that doesn't fit those
restrictions, it needs to be allocated in the main data memory...
I am not sure, I buy this argument (provided it is supposed to give guidance
on interpreting the C++ standard). The standard describes the memory model
and states the addressable units in memory are bytes. If you had the
architecture above, implementors would have to decide what they want a byte
to be, and if they decide on the smaller unit, they would have to implement
some trickery to make those subwords look like addressable in the region of
memory where hardware does not support it. From the point of the abstract
machine, memory is homogeneous.

[snip]
Best

Kai-Uwe Bux

Feb 1 '07 #37
In article <ep**********@murdoch.acc.Virginia.EDU>, jk********@gmx.net
says...

[ ... ]
I am not sure, I buy this argument (provided it is supposed to give guidance
on interpreting the C++ standard). The standard describes the memory model
and states the addressable units in memory are bytes. If you had the
architecture above, implementors would have to decide what they want a byte
to be, and if they decide on the smaller unit, they would have to implement
some trickery to make those subwords look like addressable in the region of
memory where hardware does not support it. From the point of the abstract
machine, memory is homogeneous.
While we all know the general idea of how we think things are supposed
to be, the question would be whether there's a requirement in the
standard that this design would violate.

Most people have the general idea that the required alignment of an item
is always less than or equal to the size of that item, so reading a char
will always be aligned -- but I don't see any such actual requirement. I
don't see any other requirement it would violate either.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Feb 2 '07 #38
Jerry Coffin wrote:
In article <ep**********@murdoch.acc.Virginia.EDU>, jk********@gmx.net
says...

[ ... ]
>I am not sure, I buy this argument (provided it is supposed to give
guidance on interpreting the C++ standard). The standard describes the
memory model and states the addressable units in memory are bytes. If you
had the architecture above, implementors would have to decide what they
want a byte to be, and if they decide on the smaller unit, they would
have to implement some trickery to make those subwords look like
addressable in the region of memory where hardware does not support it.
From the point of the abstract machine, memory is homogeneous.

While we all know the general idea of how we think things are supposed
to be, the question would be whether there's a requirement in the
standard that this design would violate.

Most people have the general idea that the required alignment of an item
is always less than or equal to the size of that item, so reading a char
will always be aligned -- but I don't see any such actual requirement. I
don't see any other requirement it would violate either.
I think, I see your point now: although the standard guarantees that memory
consists of bytes and each byte is invidually addressable, and although it
guarantees that an unsigned char has size 1, which means it is exactly one
byte, there is no guarantee that unsigned char has no alignment, i.e., the
standard does not guarantee that each bytes can be addressed by means of a
pointer to unsigned char.

I think, that might be a defect in the standard.
Best

Kai-Uwe Bux
Feb 2 '07 #39
In article <ep**********@murdoch.acc.Virginia.EDU>, jk********@gmx.net
says...

[ ... ]
I think, I see your point now: although the standard guarantees that memory
consists of bytes and each byte is invidually addressable, and although it
guarantees that an unsigned char has size 1, which means it is exactly one
byte, there is no guarantee that unsigned char has no alignment, i.e., the
standard does not guarantee that each bytes can be addressed by means of a
pointer to unsigned char.
Actually, I don't see anything that even says every byte is individually
addressable. It says a char is one byte, and everything else is composed
of bytes, but I don't see anything that guarantees that those bytes are
all individually addressable. It does guarantee that anything else can
be copied into bytes and those bytes addressed individually. There's an
example that does byte-by-byte copying but it's not normative. As such,
I think the intent to allow byte-by-byte addressing of all POD types was
probably there -- but I don't see normative language that really
guarantees it.

Use of the word "alignment" tends to suggest that it's related to the
least significant bits of an address. Nonetheless, the alignment rules
really seem to say that memory that's dynamically allocated (e.g. with
malloc) can be addressed as any type that'll fit into the allocated
memory, but otherwise, you can only really address something as its
allocated type. There are a few special rules about how you can address
parts of a partially constructed object, but that's about it. Oddly, I
think these are _intended_ to restrict what you can do portably, but I
think they're actually more permissive than the rules for other
situations.
I think, that might be a defect in the standard.
I suspect it is. The note mentioned above, while non-normative still
gives a _strong_ suggestion of what the authors had in mind. I think the
intent was to allow any object (in the C sense of the word) to be
addressed as a series of bytes. You're not guaranteed a particular
relationship between the original value and the values in those bytes,
but you're allowed to read them anyway.

As I've said, however, while I don't see normative language to support
that, I'm pretty sure just about every compiler writer "knows" it so
every compiler around will allow it. Systems that have memory that can't
be addressed byte-by-byte probably fake it by reading entire words and
then allowing manipulation of individual bytes in registers.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Feb 3 '07 #40
Jerry Coffin wrote:
In article <ep**********@murdoch.acc.Virginia.EDU>, jk********@gmx.net
says...

[ ... ]
>I think, I see your point now: although the standard guarantees that
memory consists of bytes and each byte is invidually addressable, and
although it guarantees that an unsigned char has size 1, which means it
is exactly one byte, there is no guarantee that unsigned char has no
alignment, i.e., the standard does not guarantee that each bytes can be
addressed by means of a pointer to unsigned char.

Actually, I don't see anything that even says every byte is individually
addressable. It says a char is one byte, and everything else is composed
of bytes, but I don't see anything that guarantees that those bytes are
all individually addressable.
I was thinking of [1.7/1]: ... Every byte has a unique address.
[very interesting non-controversial material snipped]
Best

Kai-Uwe Bux
Feb 3 '07 #41
In article <eq**********@murdoch.acc.Virginia.EDU>, jk********@gmx.net
says...

[ ... ]
I was thinking of [1.7/1]: ... Every byte has a unique address.
I'm pretty sure I didn't express what I was trying to say very well.
What I was trying to say is that this requires the implementation to
_assign_ an address to every byte, but doesn't guarantee that you can
_do_ anything with an arbitrary address. For example, a machine could
have an address range in which the smallest item it could read or write
was 32-bits. Assuming its char was 8 bits, each of those 32-bit items
would have to be given four different addresses -- even if you could
only read or write anything via one of them.

As I said, I seriously doubt anybody intended or wanted that, but I
can't think of anything in the standard it would violate.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Feb 3 '07 #42
Jerry Coffin wrote:
In article <eq**********@murdoch.acc.Virginia.EDU>, jk********@gmx.net
says...

[ ... ]
>I was thinking of [1.7/1]: ... Every byte has a unique address.

I'm pretty sure I didn't express what I was trying to say very well.
What I was trying to say is that this requires the implementation to
_assign_ an address to every byte, but doesn't guarantee that you can
_do_ anything with an arbitrary address. For example, a machine could
have an address range in which the smallest item it could read or write
was 32-bits. Assuming its char was 8 bits, each of those 32-bit items
would have to be given four different addresses -- even if you could
only read or write anything via one of them.
Hm, now you have confused me again. How would pointer arithmetic work on
that machine for

char banner [20];
for ( char * iter = &banner; iter != &banner+20; ++ iter ) {
*iter = 0;
}

(or whatever, I am not good at raw arrays and pointer so there may be syntax
issues).

I think the array is contiguous and the running pointer is not supposed to
hit any trap values within the loop.
Best

Kai-Uwe Bux

Feb 3 '07 #43
In article <eq**********@murdoch.acc.Virginia.EDU>, jk********@gmx.net
says...
Jerry Coffin wrote:
[ ... ]
I'm pretty sure I didn't express what I was trying to say very well.
What I was trying to say is that this requires the implementation to
_assign_ an address to every byte, but doesn't guarantee that you can
_do_ anything with an arbitrary address. For example, a machine could
have an address range in which the smallest item it could read or write
was 32-bits.
Note that I said "an address range" -- this wouldn't necessarily be the
case with all its memory.
Assuming its char was 8 bits, each of those 32-bit items
would have to be given four different addresses -- even if you could
only read or write anything via one of them.

Hm, now you have confused me again. How would pointer arithmetic work on
that machine for

char banner [20];
for ( char * iter = &banner; iter != &banner+20; ++ iter ) {
*iter = 0;
}

(or whatever, I am not good at raw arrays and pointer so there may be syntax
issues).
The implementation has two choices. The first is if you've defined
something as a char, it allocates it in a different address range that
allows byte-level access. In this case, your code works fine, but if you
tried something like:

int x;
char *y = &x;

y[1] = 0;

In this case, we've defined an int, so it allocates memory that's only
accessible on word boundaries. Since we'll assume it's four bytes, it
has to assign an address to each of those four bytes, so 'y[1]'
generates a meaningful address, but I don't see anything that says the
assignment has to word -- in fact, it seems to me that the alignment
rules allow it to fail. That byte has to have an address, but nothing
says we can use it. If we originally allocated the memory as an array of
char (or used malloc, etc.) then it's required to be aligned so we can
use it in this fashion -- but if we allocate it statically or
automatically for a non-char type, the access may be misaligned.

The second approach is to fundge it: read a whole 32-bit word (or
whatever) and carry out byte-level operations inside of the registers,
using bit masks, anding/oring, etc., to make the right things happen.
For example, your code above could be encoded something like:

loop:
sub r1, r1
mov r0, banner[r1]
and r0, 0xffffff00
and r0, 0xffff00ff
and r0, 0xff00ffff
and r0, 0x00ffffff
mov banner[r1], r0
cmp banner, 20
jne loop

Of course any decent compiler would figure out that the four consecutive
AND's set the whole thing to zero, and that it was never using the
previous value, so this would almost certainly end up just writing full-
words. A more interesting case would be something like:

char x[10];

x[1] += 2;

For this, the compiler would have to generate something like:

mov r0, x[0] // includes x[1]
mov r1, r0 // make a copy
and r1, 0x0000ff00 // isolate the addend
shr r1, 8 // shift it so that byte is a bottom of reg.
add r1, 2 // do the actual addition
and r0, 0xffff00ff // mask byte out of original word
shl r1, 8 // shift copy back where it belongs
or r0, r1 // or the result back into the original word
mov x[0], r0 // store the result, including 3 unchanged bytes

If x were declared volatile, however, this probably wouldn't conform
anymore, since it generates reads and writes of values that aren't
changed in the source code.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Feb 4 '07 #44

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

9
by: Christopher Benson-Manica | last post by:
I need a smart char * class, that acts like a char * in all cases, but lets you do some std::string-type stuff with it. (Please don't say to use std::string - it's not an option...). This is my...
5
by: Alex Vinokur | last post by:
"Richard Bos" <rlb@hoekstra-uitgeverij.nl> wrote in message news:4180f756.197032434@news.individual.net... to news:comp.lang.c > ben19777@hotmail.com (Ben) wrote: > > 2) Structure casted into an...
5
by: Sona | last post by:
I understand the problem I'm having but am not sure how to fix it. My code passes two char* to a function which reads in some strings from a file and copies the contents into the two char*s. Now...
2
by: Peter Nilsson | last post by:
In a post regarding toupper(), Richard Heathfield once asked me to think about what the conversion of a char to unsigned char would mean, and whether it was sensible to actually do so. And pete has...
5
by: jab3 | last post by:
(again :)) Hello everyone. I'll ask this even at risk of being accused of not researching adequately. My question (before longer reasoning) is: How does declaring (or defining, whatever) a...
12
by: GRoll35 | last post by:
I get 4 of those errors. in the same spot. I'll show my parent class, child class, and my driver. All that is suppose to happen is the user enters data and it uses parent/child class to display...
18
by: Pedro Pinto | last post by:
Hi there once more........ Instead of showing all the code my problem is simple. I've tried to create this function: char temp(char *string){ alterString(string); return string;
4
by: Paul Brettschneider | last post by:
Hello all, consider the following code: typedef char T; class test { T *data; public: void f(T, T, T); void f2(T, T, T);
16
by: s0suk3 | last post by:
This code #include <stdio.h> int main(void) { int hello = {'h', 'e', 'l', 'l', 'o'}; char *p = (void *) hello; for (size_t i = 0; i < sizeof(hello); ++i) {
29
by: Kenzogio | last post by:
Hi, I have a struct "allmsg" and him member : unsigned char card_number; //16 allmsg.card_number
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.