Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #6177 > unrolled thread
| Started by | Ruben Safir <ruben@mrbrklyn.com> |
|---|---|
| First post | 2011-06-04 05:26 +0000 |
| Last post | 2011-06-10 13:16 +0200 |
| Articles | 14 — 8 participants |
Back to article view | Back to comp.lang.c++
unions Ruben Safir <ruben@mrbrklyn.com> - 2011-06-04 05:26 +0000
Re: unions Ian Collins <ian-news@hotmail.com> - 2011-06-04 17:38 +1200
Re: unions Ruben Safir <ruben@mrbrklyn.com> - 2011-06-04 05:45 +0000
Re: unions Ian Collins <ian-news@hotmail.com> - 2011-06-04 18:04 +1200
Re: unions Ruben Safir <ruben@mrbrklyn.com> - 2011-06-04 06:13 +0000
Re: unions Öö Tiib <ootiib@hot.ee> - 2011-06-04 04:54 -0700
Re: unions Edek <edek.pienkowski@gmail.com> - 2011-06-04 19:59 +0200
Re: unions Vaclav Haisman <v.haisman@sh.cvut.cz> - 2011-06-04 20:13 +0200
Re: unions Edek <edek.pienkowski@gmail.com> - 2011-06-04 22:34 +0200
Re: unions Vaclav Haisman <v.haisman@sh.cvut.cz> - 2011-06-05 07:29 +0200
Re: unions Jorgen Grahn <grahn+nntp@snipabacken.se> - 2011-06-09 09:19 +0000
Re: unions Keith <kbelder@gmail.com> - 2011-06-09 11:17 -0700
Re: unions Victor Bazarov <v.bazarov@comcast.invalid> - 2011-06-09 14:29 -0400
Re: unions Edek <edek.pienkowski@gmail.com> - 2011-06-10 13:16 +0200
| From | Ruben Safir <ruben@mrbrklyn.com> |
|---|---|
| Date | 2011-06-04 05:26 +0000 |
| Subject | unions |
| Message-ID | <iscfn1$keo$8@reader1.panix.com> |
There are some things, that as I learned to program, I learned them,
decided they suck and would never use them, and then put them away.
unions are one of these things (static was another and complex #define
yet another).
But I took this employment exam this week and 10% of the questions
involved unions. As I understood unions, union sub-objects just step on
each other in binary in the allocated space where they exist (talk about
a snake pit for potential bugs). Am I missing something about them? I
started to have deep doubts about what I thought I knew.
union {
double x;
char a[10];
} myunion;
myunion.a[0] = 'A';
myunion.a[1] = 'A';
myunion.a[2] = 'A';
myunion.a[3] = 'A';
std::cout << myunion.x << std::end
is going to spit out some binary translation of a double with 4 bytes of
65 dec, whatever that is.
Ruben
[toc] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2011-06-04 17:38 +1200 |
| Message-ID | <94tun8FivcU7@mid.individual.net> |
| In reply to | #6177 |
On 06/ 4/11 05:26 PM, Ruben Safir wrote:
> There are some things, that as I learned to program, I learned them,
> decided they suck and would never use them, and then put them away.
> unions are one of these things (static was another and complex #define
> yet another).
>
> But I took this employment exam this week and 10% of the questions
> involved unions. As I understood unions, union sub-objects just step on
> each other in binary in the allocated space where they exist (talk about
> a snake pit for potential bugs). Am I missing something about them? I
> started to have deep doubts about what I thought I knew.
That's about right. You could view a union as a struct with all the
members having an offset of zero.
We don't use them in C++ as much as in C.
> union {
> double x;
> char a[10];
> } myunion;
>
> myunion.a[0] = 'A';
> myunion.a[1] = 'A';
> myunion.a[2] = 'A';
> myunion.a[3] = 'A';
>
> std::cout<< myunion.x<< std::end
> is going to spit out some binary translation of a double with 4 bytes of
> 65 dec, whatever that is.
Maybe, the result is undefined.
--
Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | Ruben Safir <ruben@mrbrklyn.com> |
|---|---|
| Date | 2011-06-04 05:45 +0000 |
| Message-ID | <iscgp0$keo$12@reader1.panix.com> |
| In reply to | #6182 |
On Sat, 04 Jun 2011 17:38:47 +1200, Ian Collins wrote: > std::cout<< myunion.x<< std::end >> is going to spit out some binary translation of a double with 4 bytes >> of 65 dec, whatever that is. > > Maybe, the result is undefined. why? Because it is hardware and OS dependent?
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2011-06-04 18:04 +1200 |
| Message-ID | <94u07jFivcU10@mid.individual.net> |
| In reply to | #6186 |
On 06/ 4/11 05:45 PM, Ruben Safir wrote: > On Sat, 04 Jun 2011 17:38:47 +1200, Ian Collins wrote: > >> std::cout<< myunion.x<< std::end >>> is going to spit out some binary translation of a double with 4 bytes >>> of 65 dec, whatever that is. >> >> Maybe, the result is undefined. > > why? Because it is hardware and OS dependent? What if a double was bigger than 10? -- Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | Ruben Safir <ruben@mrbrklyn.com> |
|---|---|
| Date | 2011-06-04 06:13 +0000 |
| Message-ID | <isciee$keo$13@reader1.panix.com> |
| In reply to | #6188 |
On Sat, 04 Jun 2011 18:04:35 +1200, Ian Collins wrote: >> why? Because it is hardware and OS dependent? > > What if a double was bigger than 10? Yeah - but - that's a damn bug, wasn't a choice, and don't DO that wasn't a choice either.. I don't even know why this construction was ever invented.
[toc] | [prev] | [next] | [standalone]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2011-06-04 04:54 -0700 |
| Message-ID | <4ff4056c-9fd4-408d-a87b-95e5abff1783@e21g2000vbz.googlegroups.com> |
| In reply to | #6177 |
On Jun 4, 8:26 am, Ruben Safir <ru...@mrbrklyn.com> wrote:
> There are some things, that as I learned to program, I learned them,
> decided they suck and would never use them, and then put them away.
> unions are one of these things (static was another and complex #define
> yet another).
>
> But I took this employment exam this week and 10% of the questions
> involved unions. As I understood unions, union sub-objects just step on
> each other in binary in the allocated space where they exist (talk about
> a snake pit for potential bugs). Am I missing something about them? I
> started to have deep doubts about what I thought I knew.
The union is one of tools how to create C-style polymorphism.
In C++ you have a base class (like Being) from what you derive
subclasses (like Bird and Mammal). Subclasses can have different from
each other subobjects (Mammal has tits but does not have beak, Bird
has beak but lacks tits). In C you can do similar thing with union (by
putting beak and tits into union). That is left in C++ so the code and
interfaces stay compatible.
> union {
> double x;
> char a[10];
>
> } myunion;
>
> myunion.a[0] = 'A';
> myunion.a[1] = 'A';
> myunion.a[2] = 'A';
> myunion.a[3] = 'A';
>
> std::cout << myunion.x << std::end
> is going to spit out some binary translation of a double with 4 bytes of
> 65 dec, whatever that is.
Now that is as undefined behavior as is accessing tits of a bird. ;)
[toc] | [prev] | [next] | [standalone]
| From | Edek <edek.pienkowski@gmail.com> |
|---|---|
| Date | 2011-06-04 19:59 +0200 |
| Message-ID | <isdrr3$urc$1@node2.news.atman.pl> |
| In reply to | #6177 |
Am I missing something about them? I > started to have deep doubts about what I thought I knew. > Other things aside, by the standard unions are the only possibility to alias two non-char types without breaking optimisations. Maybe void* is another and a couple of other strange cases. Don't ask me about where it is in the standard; I just know that it is a pain to find bugs caused by wrong casting coupled with unpredictable optimisation results (UB caused by casts really, unions are safe). Edek
[toc] | [prev] | [next] | [standalone]
| From | Vaclav Haisman <v.haisman@sh.cvut.cz> |
|---|---|
| Date | 2011-06-04 20:13 +0200 |
| Message-ID | <4DEA75DF.6010402@sh.cvut.cz> |
| In reply to | #6209 |
Edek wrote, On 4.6.2011 19:59: > Am I missing something about them? I >> started to have deep doubts about what I thought I knew. >> > > Other things aside, by the standard unions are the only > possibility to alias two non-char types without breaking > optimisations. Maybe void* is another and a couple of > other strange cases. Don't ask me about where it is in the > standard; I just know that it is a pain to find bugs > caused by wrong casting coupled with unpredictable optimisation > results (UB caused by casts really, unions are safe). Unions are not safe. You cannot write using one union member and read using another. It is only GCC extension that it works but the standard does not allow it, AFAIK. -- VH
[toc] | [prev] | [next] | [standalone]
| From | Edek <edek.pienkowski@gmail.com> |
|---|---|
| Date | 2011-06-04 22:34 +0200 |
| Message-ID | <ise4sq$8e7$1@node2.news.atman.pl> |
| In reply to | #6210 |
On 06/04/2011 08:13 PM, Vaclav Haisman wrote:
> Edek wrote, On 4.6.2011 19:59:
>> Am I missing something about them? I
>>> started to have deep doubts about what I thought I knew.
>>>
>>
>> Other things aside, by the standard unions are the only
>> possibility to alias two non-char types without breaking
>> optimisations. Maybe void* is another and a couple of
>> other strange cases. Don't ask me about where it is in the
>> standard; I just know that it is a pain to find bugs
>> caused by wrong casting coupled with unpredictable optimisation
>> results (UB caused by casts really, unions are safe).
> Unions are not safe. You cannot write using one union member and read using
> another. It is only GCC extension that it works but the standard does not
> allow it, AFAIK.
>
I think it here depends what is precisely meant. Code:
typedef union {
short _s;
UU* _ptr;
} UU;
1) Safe:
short ok(UU *p1, UU* p2)
{
short tmp = p2->_s; // a
p1->_ptr = p2; // b, by different type
return tmp + p1->_ptr->_s; //c
// I think this is what I meant as legal
// all access by union
// compiler knows a),b),c) may alias, same type accessed (UU)
// which causes a reread of p2->_s at c), because it may have
// been overwritten by b). No warnings.
movzwl (%rsi), %eax a)
movq %rsi, (%rdi) b)
addw (%rsi), %ax c) <--- reload of _s
ret
// Note: no reordering either, in case rdi == rsi
}
2) Also safe
short alsoOk (UU* p1)
{
UU u; // not an aliasing problem, local copy accessed
u._ptr = p1[23]->_ptr;
return u._s;
movq 184(%rdi), %rax // Trivial
ret
};
3)
short foo (UU *uu, int *p2)
{
// not allowed. Casting to union in main (below) does not mean
// the same as my above 'all access by union'
short tmp = uu->_s;
p2[42] = 0; // may overwrite uu->_s
return tmp + uu->_s; // will compiler reread uu->_s? No...
movzwl (%rdi), %eax
movl $0, 168(%rsi)
addl %eax, %eax // tmp + tmp really
}
The output of the below is:
$ ./main
Is 84
should be: 42
$
#include <iostream>
using namespace std;
extern short foo (UU*,int*);
int main ()
{
int * ints = new int[100];
for (int i = 0; i < 100; i++) ints[i]=i;
int& ourVal = ints[42];
short shouldBe = ((UU*)&ourVal)->_s; // warns
cout << "Is " << foo ((UU*)&ourVal, ints) // warns
<< endl;
shouldBe += ((UU*)&ourVal)->_s; // warns
cout << " should be: " << shouldBe << endl;
delete [] ints;
return -1;
}
Is the extension you are referring to calling foo when UU is
typedef union uu {
short _s;
union uu _ptr;
int _int;
};
? Then generated code is fine.
Correct? I'm not a language lawyer. BTW, the effect depends on whether
foo and main are compiled together or separately, and whether they are
compiled with -fPIC or not, and possibly other options.
Edek
[toc] | [prev] | [next] | [standalone]
| From | Vaclav Haisman <v.haisman@sh.cvut.cz> |
|---|---|
| Date | 2011-06-05 07:29 +0200 |
| Message-ID | <4DEB141E.7060402@sh.cvut.cz> |
| In reply to | #6213 |
Edek wrote, On 4.6.2011 22:34:
> On 06/04/2011 08:13 PM, Vaclav Haisman wrote:
>> Edek wrote, On 4.6.2011 19:59:
>>> Am I missing something about them? I
>>>> started to have deep doubts about what I thought I knew.
>>>>
>>>
>>> Other things aside, by the standard unions are the only
>>> possibility to alias two non-char types without breaking
>>> optimisations. Maybe void* is another and a couple of
>>> other strange cases. Don't ask me about where it is in the
>>> standard; I just know that it is a pain to find bugs
>>> caused by wrong casting coupled with unpredictable optimisation
>>> results (UB caused by casts really, unions are safe).
>> Unions are not safe. You cannot write using one union member and read using
>> another. It is only GCC extension that it works but the standard does not
>> allow it, AFAIK.
>>
>
> I think it here depends what is precisely meant. Code:
>
> typedef union {
> short _s;
> UU* _ptr;
> } UU;
>
> 1) Safe:
>
> short ok(UU *p1, UU* p2)
> {
> short tmp = p2->_s; // a
> p1->_ptr = p2; // b, by different type
>
>
> return tmp + p1->_ptr->_s; //c
>
> // I think this is what I meant as legal
> // all access by union
> // compiler knows a),b),c) may alias, same type accessed (UU)
> // which causes a reread of p2->_s at c), because it may have
> // been overwritten by b). No warnings.
>
> movzwl (%rsi), %eax a)
> movq %rsi, (%rdi) b)
> addw (%rsi), %ax c) <--- reload of _s
> ret
> // Note: no reordering either, in case rdi == rsi
> }
>
> 2) Also safe
>
> short alsoOk (UU* p1)
> {
> UU u; // not an aliasing problem, local copy accessed
> u._ptr = p1[23]->_ptr;
> return u._s;
This is not fine. The _s member has not been written to.
>
> movq 184(%rdi), %rax // Trivial
> ret
>
> };
>
> 3)
>
> short foo (UU *uu, int *p2)
> {
> // not allowed. Casting to union in main (below) does not mean
> // the same as my above 'all access by union'
>
> short tmp = uu->_s;
>
> p2[42] = 0; // may overwrite uu->_s
>
> return tmp + uu->_s; // will compiler reread uu->_s? No...
>
> movzwl (%rdi), %eax
> movl $0, 168(%rsi)
> addl %eax, %eax // tmp + tmp really
>
> }
>
> The output of the below is:
> $ ./main
> Is 84
> should be: 42
> $
>
>
> #include <iostream>
>
> using namespace std;
>
> extern short foo (UU*,int*);
>
> int main ()
> {
> int * ints = new int[100];
>
> for (int i = 0; i < 100; i++) ints[i]=i;
>
> int& ourVal = ints[42];
>
> short shouldBe = ((UU*)&ourVal)->_s; // warns
>
> cout << "Is " << foo ((UU*)&ourVal, ints) // warns
> << endl;
>
> shouldBe += ((UU*)&ourVal)->_s; // warns
>
> cout << " should be: " << shouldBe << endl;
>
> delete [] ints;
> return -1;
> }
>
>
>
> Is the extension you are referring to calling foo when UU is
>
> typedef union uu {
> short _s;
> union uu _ptr;
> int _int;
> };
>
> ? Then generated code is fine.
>
> Correct? I'm not a language lawyer. BTW, the effect depends on whether
> foo and main are compiled together or separately, and whether they are
> compiled with -fPIC or not, and possibly other options.
Incorrect, IMHO. When your code has UB it is broken. It might seem ok at
first or second glance but it is still broken. It might visibly break with
different compiler version, flags or platform.
--
VH
[toc] | [prev] | [next] | [standalone]
| From | Jorgen Grahn <grahn+nntp@snipabacken.se> |
|---|---|
| Date | 2011-06-09 09:19 +0000 |
| Message-ID | <slrniv141f.gtj.grahn+nntp@frailea.sa.invalid> |
| In reply to | #6177 |
On Sat, 2011-06-04, Ruben Safir wrote: > There are some things, that as I learned to program, I learned them, > decided they suck and would never use them, and then put them away. > unions are one of these things (static was another and complex #define > yet another). If you mean "static" as in "limiting visibility of functions to the translation unit", then you're missing out on things. > But I took this employment exam this week and 10% of the questions > involved unions. I hope the job didn't have to do with C++, or that you're exaggerating the 10% figure. I can't remember the last time I used unions in C++. /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o .
[toc] | [prev] | [next] | [standalone]
| From | Keith <kbelder@gmail.com> |
|---|---|
| Date | 2011-06-09 11:17 -0700 |
| Message-ID | <92e3c64e-d8e5-4dce-a994-0006f43c6416@35g2000prp.googlegroups.com> |
| In reply to | #6177 |
On Jun 3, 10:26 pm, Ruben Safir <ru...@mrbrklyn.com> wrote:
> But I took this employment exam this week and 10% of the questions
> involved unions. As I understood unions, union sub-objects just step on
> each other in binary in the allocated space where they exist (talk about
> a snake pit for potential bugs). Am I missing something about them? I
> started to have deep doubts about what I thought I knew.
I'm writing a stack based scripting language for a project,
and I'm using a union for the stack. Each slot in the stack
can hold a value that can represent a number of different types;
an integer, a function pointer, a pointer to char, or a pointer
to another stack entry.
The union definition is something like this (simplified):
union xt {
int i;
void (*f)();
char *c;
xt *p;
}
Now, I understand this is absolutely undefined behavior not guaranteed
to
work on all compilers; but as a question of practicality, it does work
on the compilers and systems I need it to work on.
It avoids a LOT of really ugly casts, and seems to be the most
efficient
way to handle the requirements. In this case, I'm using C++ to
replicate
the techniques I'd use if I was writing it in assembly... and that is
something that should be allowed (although discouraging it is
reasonable).
I'm bracing myself for universal condemnation of my approach...
[toc] | [prev] | [next] | [standalone]
| From | Victor Bazarov <v.bazarov@comcast.invalid> |
|---|---|
| Date | 2011-06-09 14:29 -0400 |
| Message-ID | <isr3dv$tck$1@dont-email.me> |
| In reply to | #6511 |
On 6/9/2011 2:17 PM, Keith wrote:
> On Jun 3, 10:26 pm, Ruben Safir<ru...@mrbrklyn.com> wrote:
>
>> But I took this employment exam this week and 10% of the questions
>> involved unions. As I understood unions, union sub-objects just step on
>> each other in binary in the allocated space where they exist (talk about
>> a snake pit for potential bugs). Am I missing something about them? I
>> started to have deep doubts about what I thought I knew.
>
>
> I'm writing a stack based scripting language for a project,
> and I'm using a union for the stack. Each slot in the stack
> can hold a value that can represent a number of different types;
> an integer, a function pointer, a pointer to char, or a pointer
> to another stack entry.
>
> The union definition is something like this (simplified):
>
> union xt {
> int i;
> void (*f)();
> char *c;
> xt *p;
> }
>
> Now, I understand this is absolutely undefined behavior not guaranteed
> to
> work on all compilers; but as a question of practicality, it does work
> on the compilers and systems I need it to work on.
Can you elaborate on *what* is "absolutely undefined behavior"? You
haven't actually described any behavior. You just said what you store
in those units.
> It avoids a LOT of really ugly casts, and seems to be the most
> efficient
> way to handle the requirements. In this case, I'm using C++ to
> replicate
> the techniques I'd use if I was writing it in assembly... and that is
> something that should be allowed (although discouraging it is
> reasonable).
>
> I'm bracing myself for universal condemnation of my approach...
What approach?
V
--
I do not respond to top-posted replies, please don't ask
[toc] | [prev] | [next] | [standalone]
| From | Edek <edek.pienkowski@gmail.com> |
|---|---|
| Date | 2011-06-10 13:16 +0200 |
| Message-ID | <issud7$q6k$1@node2.news.atman.pl> |
| In reply to | #6511 |
>
> The union definition is something like this (simplified):
>
> union xt {
> int i;
> void (*f)();
> char *c;
> xt *p;
> }
>
> Now, I understand this is absolutely undefined behavior not guaranteed
> to
> work on all compilers; but as a question of practicality, it does work
> on the compilers and systems I need it to work on.
I don't see why this should be undefined behaviour based on what you
wrote; I do not know how you intend to use the union, that may be
undefined, but in general using unions in C++ is not undefined
behaviour. As someone wrote in this thread before, if, for every
'instance', if you read the same thing as you wrote to it - ie.
write function pointer, read function pointer - it is just fine.
Otherwise there would be no point in using unions in C++, no?
I think the pattern could be:
struct {
int actualType;
union {
type1 _t1;
type2 _t2;
} val;
};
Then, based on actualType, you can read safely the right type,
assuming you set the actualType to some enum value which is appropriate.
Maybe actualType could be avoided if the 'type' of the union can
be determined from context, e.g. you don't dump the union to string,
and you don't need to double check the 'type' either.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c++
csiph-web