Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   structure and union queries (http://www.velocityreviews.com/forums/t678976-structure-and-union-queries.html)

Tagore 04-07-2009 09:07 PM

structure and union queries
 
hi,
Please consider 2 programs below and queries assoicated with them:
PROGRAM-1:
#include<stdio.h>
typedef union
{
float f1;
float f2;
int i;
}sample;
int main()
{
sample S={66};
printf("%f %f %d",S.f1,S.f2,S.i);
return 0;
}

OUTPUT:
66.000000 66.000000 1115947008
I feel myself unable to understand above output...I expected that as
we are initializing S with 66 ,a integer, so It should print first two
grabage value when printing floating values.and then print 66 but I
found it otherwise here.

PROGRAM-2:
#include<stdio.h>
typedef struct sample
{
int i;
char a[10];
}data;
int main()
{
printf("%d", sizeof(data.a));
return 0;
}
OUTPUT:
In function 'main':
Line 10: error: expected ')' before '.' token
I expected output of this function to be 10 which is size of array
a....but could not understand this error.

Please help me regarding both queries

Ze Long 04-07-2009 09:37 PM

Re: structure and union queries
 
Tagore 写道:
> hi,
> Please consider 2 programs below and queries assoicated with them:
> PROGRAM-1:
> #include<stdio.h>
> typedef union
> {
> float f1;
> float f2;
> int i;
> }sample;
> int main()
> {
> sample S={66};
> printf("%f %f %d",S.f1,S.f2,S.i);
> return 0;
> }
>
> OUTPUT:
> 66.000000 66.000000 1115947008
> I feel myself unable to understand above output...I expected that as
> we are initializing S with 66 ,a integer, so It should print first two
> grabage value when printing floating values.and then print 66 but I
> found it otherwise here.
>
> PROGRAM-2:
> #include<stdio.h>
> typedef struct sample
> {
> int i;
> char a[10];
> }data;
> int main()
> {
> printf("%d", sizeof(data.a));
> return 0;
> }
> OUTPUT:
> In function 'main':
> Line 10: error: expected ')' before '.' token
> I expected output of this function to be 10 which is size of array
> a....but could not understand this error.
>
> Please help me regarding both queries


I don't know how does union work. But for the second program, you are
defining a type named data, not a structure. The right way to do this is
struct sample
{
int i;
char a[10];
}data;

Notice there is not "typedef" in the first line.

jameskuyper 04-07-2009 09:53 PM

Re: structure and union queries
 
Tagore wrote:
> hi,
> Please consider 2 programs below and queries assoicated with them:
> PROGRAM-1:
> #include<stdio.h>
> typedef union
> {
> float f1;
> float f2;
> int i;
> }sample;
> int main()
> {
> sample S={66};


This code initializes S.f1 with a value of 66.0.

> printf("%f %f %d",S.f1,S.f2,S.i);


Any attempt to use the value of S.f2 or s.i at this point in the
program has undefined behavior. The only member of a union that you
can safely read is the member that was last written to.

> return 0;
> }
>
> OUTPUT:
> 66.000000 66.000000 1115947008
> I feel myself unable to understand above output...I expected that as
> we are initializing S with 66 ,a integer, so It should print first two
> grabage value when printing floating values.and then print 66 but I
> found it otherwise here.


The rule for initializing unions is that it's always the first member
of the union that gets initialized, unless you specify otherwise (the
ability to specify a different member is a C99 feature); the type of
the initializer is irrelevant. The initializer is implicitly converted
to the type of that member, as-if by assignment. In other words, your
code is equivalent to

sample S;
S.f1 = 66;

If you want to intialize i at the same time you define S, you can't do
it in C90. In C99 you can write:
sample S = {.i=66};

> PROGRAM-2:
> #include<stdio.h>
> typedef struct sample
> {
> int i;
> char a[10];
> }data;
> int main()
> {
> printf("%d", sizeof(data.a));


This is the wrong format specifier to use. %d is for 'int'. The value
of a sizeof expression has the type size_t, which is an unsigned
integer type, and often one that is incompatible with 'int'. As a
result, your printf() call has undefined behavior. See below for two
different options for dealing with this problem.

> return 0;
> }
> OUTPUT:
> In function 'main':
> Line 10: error: expected ')' before '.' token
> I expected output of this function to be 10 which is size of array
> a....but could not understand this error.


You've defined 'data' to be a typedef for struct sample. You can write
"sizeof(type)" or "sizeof expression", but data.a is neither a type
nor an expression, it's a constraint violation. The left operand of
the '.' operator must be an expression which has a struct or union
type. 'data' is a type, not an expression. It IS a struct type; it is
not an expression which has struct type.

What you can do is write an expression whose type is the type of 'a':

/* Use this form only for C90; unsigned long might not be big
enough in C99. */
printf("%lu", (unsigned long)sizeof ((data *)NULL)->a);

/* Use this form only for C99; %z is not supported in C90. */
printf("%zu", sizeof ((data *)NULL)->a);

Those expressions look like they dereference null pointers, but the
operand of a sizeof expression is not evaluated, (except in C99, and
even then, only if the expression involves a VLA). The only thing
"sizeof expression" does is determine what the type of the expression
would be, if it were evaluated, so those expressions are perfectly
safe.

Jens Thoms Toerring 04-07-2009 10:00 PM

Re: structure and union queries
 
Tagore <c.lang.myself@gmail.com> wrote:
> Please consider 2 programs below and queries assoicated with them:
> PROGRAM-1:
> #include<stdio.h>
> typedef union
> {
> float f1;
> float f2;
> int i;
> }sample;
> int main()
> {
> sample S={66};
> printf("%f %f %d",S.f1,S.f2,S.i);
> return 0;
> }


> OUTPUT:
> 66.000000 66.000000 1115947008
> I feel myself unable to understand above output...I expected that as
> we are initializing S with 66 ,a integer, so It should print first two
> grabage value when printing floating values.and then print 66 but I
> found it otherwise here.


No, just because there's an int in the union and the value you use
for the initializaton is an int, the int member of the union isn't
initialized automatically. To cite C standard: "A brace-enclosed
initializer for a union object initializes the member that appears
first in the declaration list of the union type." That means that
in your case the 'f1' member of the union gets initialized (after
converting 66 to a float value).

Please also note that taking the value of the element of an union
that wasn't the last one to be assigned a value to results in
undefined behaviour - rather likely not a problem here with this
test program but better avoided in a real program.

> PROGRAM-2:
> #include<stdio.h>
> typedef struct sample
> {
> int i;
> char a[10];
> }data;
> int main()
> {
> printf("%d", sizeof(data.a));
> return 0;
> }
> OUTPUT:
> In function 'main':
> Line 10: error: expected ')' before '.' token
> I expected output of this function to be 10 which is size of array
> a....but could not understand this error.


You can only apply 'sizeof' to either a type or a variable.
Here 'data' would be a type, but 'data.a' isn't. On the other
hand, if you would create an instance of the structure, like

data mydata;

you then could do

printf( "%lu", ( unsigned long ) sizeof mydata.a q);

Please note the cast of 'sizeof' and the use of "%lu" - what
'sizeof' results in may not be (and often isn't) an int and
lying to printf() (or other variadic functions) is never a
good idea...
Regards, Jens
--
\ Jens Thoms Toerring ___ jt@toerring.de
\__________________________ http://toerring.de

Keith Thompson 04-07-2009 10:01 PM

Re: structure and union queries
 
Tagore <c.lang.myself@gmail.com> writes:
> Please consider 2 programs below and queries assoicated with them:
> PROGRAM-1:
> #include<stdio.h>
> typedef union
> {
> float f1;
> float f2;
> int i;
> }sample;
> int main()
> {
> sample S={66};
> printf("%f %f %d",S.f1,S.f2,S.i);
> return 0;
> }
>
> OUTPUT:
> 66.000000 66.000000 1115947008
> I feel myself unable to understand above output...I expected that as
> we are initializing S with 66 ,a integer, so It should print first two
> grabage value when printing floating values.and then print 66 but I
> found it otherwise here.


The initializer initializes the *first* member of the union (not the
first one that happens to match the expression's type). In this case,
the int value 66 is converted to float, so S.f1 is 66.0. S.f2, since
it's of the same type and occupies the same location in memory, also
has the value 66.0. S.i has whatever int value corresponds to the
float representation of 66.0 (in this case, apparently that's
1115947008, or 0x42840000).

> PROGRAM-2:
> #include<stdio.h>
> typedef struct sample
> {
> int i;
> char a[10];
> }data;
> int main()
> {
> printf("%d", sizeof(data.a));
> return 0;
> }
> OUTPUT:
> In function 'main':
> Line 10: error: expected ')' before '.' token
> I expected output of this function to be 10 which is size of array
> a....but could not understand this error.


"data" is a type. You can't legally refer to data.a. You have to
have an object or expression of type data; then you can refer to a
member of that object or expression.

To take a simpler example:

typedef struct {
int i;
} my_type;

my_type my_object;

"my_type.i" is invalid, even as an argument to sizeof. "my_object.i"
is valid; it refers to the i member of the object "my_object".

(If "sizeof(my_type.i)" were legal, presumably it would give you the
size of the i member of the type my_type. But it isn't, so it
doesn't.)

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Keith Thompson 04-07-2009 10:22 PM

Re: structure and union queries
 
jt@toerring.de (Jens Thoms Toerring) writes:
[...]
> You can only apply 'sizeof' to either a type or a variable.


Quibble: you can apply 'sizeof' either to a type (which must be in
parentheses) or to an expression (specifically a unary-expression).
For example, ``sizeof 42'' is legal, though 42 is neither a type nor a
variable.

> Here 'data' would be a type, but 'data.a' isn't.

[...]

The problem is that ``data.a'' is illegal, since the left operand of
"." must be an expression, and data is a type name. The fact that
it's being used as the operand of "sizeof" doesn't enter into it;
``data.a'' is illegal in any context.

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

lawrence.jones@siemens.com 04-08-2009 04:05 PM

Re: structure and union queries
 
jameskuyper <jameskuyper@verizon.net> wrote:
>
> Any attempt to use the value of S.f2 or s.i at this point in the
> program has undefined behavior. The only member of a union that you
> can safely read is the member that was last written to.


That was the rule in C90, but the rules in C99 recognize what really
happens -- the existing bits are reinterpreted in the other type. Since
f2 has the same type as the member that was last written to, the
behavior of accessing it is completely defined. Accessing i is a bit
more fluid; since the types are different, the existing bits may or may
not be a valid representation. If they are, the behavior is well
defined but the resulting value is unspecified. If not, all bets are
off and you still get undefined behavior.
--
Larry Jones

There's never enough time to do all the nothing you want. -- Calvin

Flash Gordon 04-08-2009 11:21 PM

Re: structure and union queries
 
Joe Wright wrote:
> lawrence.jones@siemens.com wrote:
>> jameskuyper <jameskuyper@verizon.net> wrote:
>>> Any attempt to use the value of S.f2 or s.i at this point in the
>>> program has undefined behavior. The only member of a union that you
>>> can safely read is the member that was last written to.

>>
>> That was the rule in C90, but the rules in C99 recognize what really
>> happens -- the existing bits are reinterpreted in the other type. Since
>> f2 has the same type as the member that was last written to, the
>> behavior of accessing it is completely defined. Accessing i is a bit
>> more fluid; since the types are different, the existing bits may or may
>> not be a valid representation. If they are, the behavior is well
>> defined but the resulting value is unspecified. If not, all bets are
>> off and you still get undefined behavior.

>
> I still don't get it.
>
> union s {
> float f;
> int i;
> };
>
> union s S;
> S.f = 66;
>
> The union S is essentially a 32-bit object with two names.


On your implementation, possibly.

> The above
> assignment will set the bits of S like this..
>
> 01000010 10000100 00000000 00000000
>
> If I then printf("%d\n", S.i) I will get..
>
> 1115947008


What if int is 64 bits but float only 32? What if int has a trap
representation (as allowed by the standard) and you pick a float that
happens to be represented by that particular bit pattern?

> and then printf("%f\n", S.f) I will get..
>
> 66.000000
>
> I read S.i first, after assigning to S.f. Assuming float and int are
> both 32 bits, what about the foregoing is undefined behavior? What can
> possibly be wrong with it?


You happen to use a float value that produces a bit pattern that is not
a valid representation for an int as Lawrence said, i.e it is a trap
representation. If there are no trap representations on your
implementation then you won't get undefined behaviour.
--
Flash Gordon

jameskuyper 04-08-2009 11:23 PM

Re: structure and union queries
 
Joe Wright wrote:
> lawrence.jones@siemens.com wrote:

....
> > That was the rule in C90, but the rules in C99 recognize what really
> > happens -- the existing bits are reinterpreted in the other type. Since
> > f2 has the same type as the member that was last written to, the
> > behavior of accessing it is completely defined. Accessing i is a bit
> > more fluid; since the types are different, the existing bits may or may
> > not be a valid representation. If they are, the behavior is well
> > defined but the resulting value is unspecified. If not, all bets are
> > off and you still get undefined behavior.

>
> I still don't get it.
>
> union s {
> float f;
> int i;
> };
>
> union s S;
> S.f = 66;
>
> The union S is essentially a 32-bit object with two names. The above
> assignment will set the bits of S like this..
>
> 01000010 10000100 00000000 00000000
>
> If I then printf("%d\n", S.i) I will get..
>
> 1115947008
>
> and then printf("%f\n", S.f) I will get..
>
> 66.000000
>
> I read S.i first, after assigning to S.f. Assuming float and int are
> both 32 bits, what about the foregoing is undefined behavior?


The fact that float and int are two different types.

> What can
> possibly be wrong with it?


The C standard merely allows it to go wrong, because there are real
implementations where it can go wrong. Potential problems include the
possibility that a valid value for an 'int' might be represented by a
bit pattern which represents an invalid value for a float (or vice
versa). The C standard calls these bit patterns "trap
representations", and any attempt to use an lvalue of a given type to
retrieve the value of a piece of memory that contains a trap
representation for that type has undefined behavior. There are real
implementations where either 'int' or 'float' has trap
representations, and where attempting to load an invalid bit pattern
will produce seriously nasty consequences.

Even on platforms without such exotic hardware, the fact that the
standard says that this has undefined behavior indirectly opens up
other possible failure modes. For instance, it gives implementations
permission to perform optimizations that would otherwise be illegal.
Example:

S.f = 66.0F;
// Compiler leaves a copy of 66.0 in a floating point register.
S.i = -3;
printf("%f\n", S.f)

Since the behavior is undefined if you attempt to read S.f when the
most recent write was to S.i, the compiler can perform an optimization
based upon the assumption that you have NOT performed such a write
(even though it's perfectly obvious that you have - the compiler is
not required to pay attention to such things when the behavior is
undefined). Specifically, it sees that the last time a value was
written to 'S.f', that value was stored in a specific register, and
that register has not been used for any other purpose since then.
Since there is no code with defined behavior that could have changed
the value of 'f' since that time, it can legally pass the value of
66.0 that was stored in the floating point register to printf(). In
other words, it's not required to notice that S.i occupies the same
piece of memory as S.f when making this decision.

This is a simple case, where such an "optimization" might seem
perverse. However, it might significantly simplify the design of the
compiler code that performs this optimization, if it doesn't have to
bother checking for possibilities that have undefined behavior. As
long as the optimization works correctly whenever the behavior is
defined, such an optimization does not prevent a compiler from being
conforming.

This is an a example of a more general rule: whenever the C standard
says that a given piece of code has undefined behavior, it gives
implementations permission to simplify their compilers by not
bothering to handle such code in the way you might naively think was
correct. As a result, the simple fact that code has undefined behavior
opens up failure modes in addition to the ones that were the original
reason the committee decided to make the behavior undefined.

CBFalconer 04-09-2009 12:20 AM

Re: structure and union queries
 
Joe Wright wrote:
>

.... snip ...
>
> I still don't get it.
>
> union s {
> float f;
> int i;
> };
>
> union s S;
> S.f = 66;
>
> The union S is essentially a 32-bit object with two names. The
> above assignment will set the bits of S like this..
>
> 01000010 10000100 00000000 00000000
>
> If I then printf("%d\n", S.i) I will get..
>
> 1115947008
>
> and then printf("%f\n", S.f) I will get..
>
> 66.000000
>
> I read S.i first, after assigning to S.f. Assuming float and int
> are both 32 bits, what about the foregoing is undefined behavior?
> What can possibly be wrong with it?


The 'wrong' thing is some idiot assuming that the access to S.f
magically reorganizes the bits in S to form the integer 66. There
are more and more of these idiots around, who have no idea what
really goes on, and who depend on the use of 'SHAZAM'.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.




All times are GMT. The time now is 08:06 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.