Strange behaviour of printf. See the code below and please tell why it behaves in this way.

D

DeltaOne

#include<stdio.h>
typedef struct test{
int i;
int j;
}test;

main(){
test var;
var.i=10;
var.j=20;

printf("i==%d i==%d \n",var,var.i);
return 1;
}

Compiler in VC++ and see that you get the output is i==10 i==20

Can any one explain Why this thing happens?even though i give the
address of var.i why the value of j is geting printed?
 
P

pete

DeltaOne said:
#include<stdio.h>
typedef struct test{
int i;
int j;
}test;

main(){
test var;
var.i=10;
var.j=20;

printf("i==%d i==%d \n",var,var.i);
return 1;
}

Compiler in VC++ and see that you get the output is i==10 i==20

Can any one explain Why this thing happens?even though i give the
address of var.i

You're not.
(int *)&var is the address of var.i.
&var.i is the address of var.i.
why the value of j is geting printed?

Even if you were giving it the address of var.i,
%d is for int type arguments, not pointers,
so the meaning of your code is undefined
and anything can happen.
 
M

Markus Moll

Hello
#include<stdio.h>
typedef struct test{
int i;
int j;
}test;

main(){
test var;
var.i=10;
var.j=20;

printf("i==%d i==%d \n",var,var.i);
return 1;
}

Compiler in VC++ and see that you get the output is i==10 i==20

VC++ ought to reject this code, as it is not valid C++. However, you're
asking in a C group about C code, so I assume you really want to compile
this as a C program. Then the compiler should warn for several reasons.

Firstly, as far as I know, implicit int declaration is discouraged even in
C. Secondly, the compiler will notice that the arguments of printf don't
match the format string. This is also the reason for the observed
behaviour.
You're supplying a struct test, then an int. printf expects two ints.
Now accidentally your struct test is nothing but two ints (i and j).
These are printed.

GCC says:
7: warning: return type defaults to `int'
In function `main':
12: warning: int format, test arg (arg 2)
Can any one explain Why this thing happens?even though i give the
address of var.i why the value of j is geting printed?

You're not giving any addresses.
This would require a pointer, like &var.i.

Markus
 
F

Flash Gordon

DeltaOne said:
#include<stdio.h>
typedef struct test{
int i;
int j;
}test;

main(){
test var;
var.i=10;
var.j=20;

printf("i==%d i==%d \n",var,var.i);
return 1;
}

Compiler in VC++ and see that you get the output is i==10 i==20

Can any one explain Why this thing happens?even though i give the
address of var.i why the value of j is geting printed?

It is happening because you invoked undefined behaviour on your specific
system before 18th May 2005. I would suggest not trying it tomorrow as
it might cause a dark lord of the Sith to come round and kill you.

Specifically, you passed var which is a struct to printf when in the
format specifier you promised to pass an int.
 
C

Chris Croughton

#include<stdio.h>
typedef struct test{
int i;
int j;
}test;

main(){

For a start, main should be declared as int main(void) (or the two
argument version). "Implicit int" is not supported in later (C99)
compilers. This isn't the problem, but is good practice to do always.
test var;
var.i=10;
var.j=20;

printf("i==%d i==%d \n",var,var.i);

Your compiler should give a diagnostic here. GCC, for instance, will
give:

warning: int format, test arg (arg 2)

if you turn warnings on telling you that there's a mismatch.
return 1;

Returning 1 from main() is not specified, the only guaranteed values
supported are zero, EXIT_SUCCESS and EXIT_FAILURE (the latter two
defined in stdlib.h).
}

Compiler in VC++ and see that you get the output is i==10 i==20

Can any one explain Why this thing happens?even though i give the
address of var.i why the value of j is geting printed?

You don't give the address, you pass the structure 'var' by value. As
it happens, this structure is two ints so it looks to printf like
passing var.i and var.j as parameters (with an extra var.i on the end
which is ignored). Other compilers might do other things, including
crash at runtime, if you pass a structure to printf()...

Chris C
 
P

pete

Chris said:
On 17 May 2005 05:03:00 -0700, DeltaOne


Your compiler should give a diagnostic here.

It's a good thing to warn about
but it's not required by the rules of C.
 
S

SM Ryan

# #include<stdio.h>
# typedef struct test{
# int i;
# int j;
# }test;
#
# main(){
# test var;
# var.i=10;
# var.j=20;
#
# printf("i==%d i==%d \n",var,var.i);
# return 1;
# }
#
# Compiler in VC++ and see that you get the output is i==10 i==20
#
# Can any one explain Why this thing happens?even though i give the
# address of var.i why the value of j is geting printed?

When you pass a struct by value, all the fields of the struct are placed in
the argument list in order, along with any padding. Your call is equivalent to

printf("i==%d i==%d \n",var.i,var.j,var.i);
 
K

Keith Thompson

SM Ryan said:
When you pass a struct by value, all the fields of the struct are
placed in the argument list in order, along with any padding. Your
call is equivalent to

printf("i==%d i==%d \n",var.i,var.j,var.i);

[ Obnoxious '#' quoting character altered, obnoxious long lines
reformatted. ]

It probably happens to behave equivalently on the OP's particular
implementation. The call invokes undefined behavior, and could behave
differently for any of a number of reasons. Just a few possibilities
off the top of my head:

The order in which arguments are passed could differ from the
order in which struct members are allocated.

Integer arguments could occupy more than sizeof(int) bytes on the
stack (for example, if int is 32 bits but the CPU works more
naturally with 64-bit quantities).

Arguments could be passed in registers (this is admittedly less
likely for functions with a variable number of arguments).

Structures, like all parameters, are passed by value, but the
value actually passed to the function (on the machine level) could
be the address of a copy of the structure.

It's true that the behavior the OP saw is one of the more likely forms
that this undefined behavior can take.
 
K

Kevin D. Quitt

Boy, this is my day for disagreeing with the gurus.
The order in which arguments are passed could differ from the
order in which struct members are allocated.

Would not this violate the as-if rule?

Structures, like all parameters, are passed by value, but the
value actually passed to the function (on the machine level) could
be the address of a copy of the structure.

This definitely would violate the as-if rule. Changes to the fields of the
struct would be made to the original data.
 
A

Anonymous 7843

Boy, this is my day for disagreeing with the gurus.


Would not this violate the as-if rule?

^^^^

This definitely would violate the as-if rule. Changes to the fields of the
struct would be made to the original data.
 
E

Emmanuel Delahaye

DeltaOne wrote on 17/05/05 :
#include<stdio.h>
typedef struct test{
int i;
int j;
}test;

main(){
test var;
var.i=10;
var.j=20;

printf("i==%d i==%d \n",var,var.i);
return 1;
}

Considering this

main.c: In function `main_':
main.c:23: warning: int format, test arg (arg 2)

The behaviour is undefined.

All bets are off.

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

..sig under repair
 
E

Emmanuel Delahaye

SM Ryan wrote on 18/05/05 :
When you pass a struct by value, all the fields of the struct are placed in
the argument list in order, along with any padding. Your call is equivalent
to

printf("i==%d i==%d \n",var.i,var.j,var.i);

No. The behaviour is undefined. Period.

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"Mal nommer les choses c'est ajouter du malheur au
monde." -- Albert Camus.
 
K

Keith Thompson

Kevin D. Quitt said:
Boy, this is my day for disagreeing with the gurus.


Would not this violate the as-if rule?

No, I don't see how. The code in question passed a
struct {int i; int j; }
value to a function expecting two ints. The standard requires j to
have a higher address and offset within the structure than j; it says
nothing about the relative addresses of two int arguments.
This definitely would violate the as-if rule. Changes to the fields of the
struct would be made to the original data.

I said the address of *a copy of* the structure. Changing the copy
would have no effect on the the original.
 
K

Keith Thompson

Keith Thompson said:
No, I don't see how. The code in question passed a
struct {int i; int j; }
value to a function expecting two ints. The standard requires j to
have a higher address and offset within the structure than j; it says
nothing about the relative addresses of two int arguments.

That was a typo; I meant that j has a higher offset than *i*.
 
S

SM Ryan

# No. The behaviour is undefined. Period.

How wonderfully unhelpful.
Actually anti-helpful.

A question was asked on an observed behaviour, so the behaviour was defined
on that implementation.
 
P

Peter Nilsson

SM said:
# No. The behaviour is undefined. Period.

How wonderfully unhelpful.
Actually anti-helpful.

A question was asked on an observed behaviour, so the behaviour was
defined on that implementation.

No, the only thing you can say was that behaviour was _observed_.

Defined behaviour is predictable and generally reproducable. Undefined
behaviour does not guarantee that. The OP may well change their mp3
player settings or such and observe completely different behaviour from
a piece of C code with undefined behaviour. [No, I'm not joking. Such
capriciousness is not unheard of.]

Modern computing has long moved past the era of defining language
behaviour in terms of what is observed on a given implementation.

It is dangerous to encourage the thought that because a given behaviour
is observed on a given machine, that other machines (or even the same
machine with a slightly different setup) will produce the same results.

Programs should be _demonstrably_, i.e. provably, correct as much as
possible. Where code goes beyond the standards, such code should be
justified in terms of other authoritative documentation, _not_
empirical
observation.
 
K

Keith Thompson

SM Ryan said:
How wonderfully unhelpful.
Actually anti-helpful.

A question was asked on an observed behaviour, so the behaviour was defined
on that implementation.

[ Obnoxious quoting character '#' changed to '>'. ]

It's only unhelpful if you're not willing to learn from it.

The behavior is undefined. That doesn't mean it's not useful to
understand why it behaves the way it does on a particular
implementation; that can be a valuable way to track down the bug. But
understanding that passing a struct { int i; int j; } to a function
that expects two int arguments happens to behave a particular way on a
particular implementation is the beginning of understanding the
problem, not the end of it.

In your earlier followup, you wrote:

When you pass a struct by value, all the fields of the struct are
placed in the argument list in order, along with any padding. Your
call is equivalent to

printf("i==%d i==%d \n",var.i,var.j,var.i);

In fact, it is equivalent only by coincidence, and only under some
implementations. The behavior is "defined" on that implementation
only if the documentation explicitly guarantees the behavior. The OP
could easily have inferred that his code was valid; that's worse than
unhelpful.
 
S

SM Ryan

# SM Ryan wrote:
# >
# > # No. The behaviour is undefined. Period.
# >
# > How wonderfully unhelpful.
# > Actually anti-helpful.
# >
# > A question was asked on an observed behaviour, so the behaviour was
# > defined on that implementation.
#
# No, the only thing you can say was that behaviour was _observed_.

No it was defined in that implementation. Once you have some real world experience,
you will discover argument list and argument passing are always meticulously
well defined in each implementation. This allows linkages between the code of
one compiler and another--an important real world consideration. Often the
argument passing is not even left up the compiler: the CPU designer defines
external linkage protocols and all compilers for that CPU. Internal linkages,
in C that would mean calling a static function, can follow alternate protocols
but often don't except for optimising compilers.

# Defined behaviour is predictable and generally reproducable. Undefined

External linkages for a CPU are very predictable. They are usually defined
above the needs of C because they are intended to serve all languages on the
CPU.

You could gently point out to the original poster that external linkage
protocols might differ on different machines, but this would not change
the well-definedness of the observed behaviour. And anybody with any kind
of compiler writing experience would quickly understand from the observations
what had happenned. That your own knowledge is too limited is perhaps a good
reason to butt out.

# behaviour does not guarantee that. The OP may well change their mp3
# player settings or such and observe completely different behaviour from
# a piece of C code with undefined behaviour. [No, I'm not joking. Such
# capriciousness is not unheard of.]

Any CPU and/or compiler like that would be deemed broken and a commercial
failure.

# It is dangerous to encourage the thought that because a given behaviour
# is observed on a given machine, that other machines (or even the same
# machine with a slightly different setup) will produce the same results.

You can always point that out in a gentle and polite fashion.

Screaming off with their topic! off with their topic! like some kind of
manical red queen gives no help whatsoever and only contributes to the
ant-social behaviour and cliqueness of the modern comp.lang.c.
 
K

Kevin D. Quitt

Zero for two.

I said the address of *a copy of* the structure. Changing the copy
would have no effect on the the original.

Yep. I need new glasses. Or eyes. Or brain.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top