[net.lang.c] C question

paulh@tektronix.UUCP (Paul Hoefling) (04/05/85)

I was trying to send this to Dennis Ritchie, but I can't seem to find a
path to him.  So, I'll open it up for net discussion (and flames :-) ).

We've got a raging controversy going on here at Tektronix, and I thought
that I would appeal to you for an 'official' opinion.

---------------------------
The controversy:

An inexperienced C programmer wrote a program containing the following:

	x = x++;

Assuming that x originally had the value 5, what should the value be after
execution of the above expression ?

---------------------------
The arguments:

In favor of 5:
	According to the operator precedence table in K&R on page 49, the ++
operator has higher precedence than the = operator.  Hence the sequence of
operations should be:
	evaluate x (value == 5)
	increment x (x now == 6)
	assign the computed value to x (x now == 5 again)

In favor of 6:
	In K&R on page 42, the text says: "But the expression ++n increments n
*before* using its value, while n++ increments n *after* its value has been
used."  Hence, the sequence of operations should be:
	evaluate x (value == 5)
	assign the computed value to x (x still == 5)
	increment x (x now == 6)

---------------------------
Therefore, if the compiler writer follows the precedence table, 5 wins, and if
s/he follows the text, either could win.  Is there an 'official' opinion, and
if so, what is it ?

We are most interested in your response.

I would like to point out that the various compilers around here have been
tried, and we have 1 vote for 6 (our 4.2BSD compiler), and 3 votes for 5
(various microprocessor compilers).

If you send mail to me at ...!tektronix!paulh, I will collect the responses
and summarize for the net.

If Dennis Ritchie is out there somewhere, I would *really* appreciate his
opinion on the subject.
-- 

Paul Hoefling   (...!tektronix!paulh)
Information Pack Rat

dad@aluxp.UUCP (DAPKUS) (04/07/85)

> We've got a raging controversy going on here at Tektronix, and I thought
> that I would appeal to you for an 'official' opinion.
> 
> An inexperienced C programmer wrote a program containing the following:
> 
> 	x = x++;
> 
> Assuming that x originally had the value 5, what should the value be after
> execution of the above expression ?
> ...
> I would like to point out that the various compilers around here have been
> tried, and we have 1 vote for 6 (our 4.2BSD compiler), and 3 votes for 5
> (various microprocessor compilers).
> ...
> Paul Hoefling   (...!tektronix!paulh)

   I am fairly new to C,  but by some random experimenting I witnessed a
strange Phenomenon.  The following program outputs a "5" on a VAX under SVR2:

main () {
	int x;
	x = 5;
	x = x++;
	printf ("%d\n", x);
}

The active part of the generated assembly code was:

	movl	$5,-4(fp)
	movl	-4(fp),r0
	incl	-4(fp)
	movl	r0,-4(fp)

The following code on the same system outputs 6.  The
only difference is that x is made a register-class:

main () {
	register int x;
	x = 5;
	x = x++;
	printf ("%d\n", x);
}

That generates:

	movl	$5,r11
	movl	r11,r11
	incl	r11

Doesn't it seem slightly paradoxical and dangerous that using "register"
in this case alters the output of the program so entirely?  Also how
about that redundant "movl r11,r11" generated in the register version?

					Donald A. Dapkus
					   aluxp!dad

henry@utzoo.UUCP (Henry Spencer) (04/07/85)

Note that section 7 of K&R Appendix A says explicitly that the order
of side effects within an expression is undefined and is up to the
compiler.  The ANSI C-standard drafts contain similar although more
elaborate wording.  The value of x after:

	x = 5;
	x = x++;

is not 5 or 6, it is "5 or 6".  It is most unwise to write code that
relies on one particular choice.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

ndiamond@watdaisy.UUCP (Norman Diamond) (04/08/85)

> An inexperienced C programmer wrote a program containing the following:
> 
> 	x = x++;
> 
> Assuming that x originally had the value 5, what should the value be after
> execution of the above expression ?
> 
> In favor of 5:
> 	According to the operator precedence table in K&R on page 49, the ++
> operator has higher precedence than the = operator.  Hence the sequence of
> operations should be:
> 	evaluate x (value == 5)
> 	increment x (x now == 6)
> 	assign the computed value to x (x now == 5 again)
> 
> In favor of 6:
> 	In K&R on page 42, the text says: "But the expression ++n increments n
> *before* using its value, while n++ increments n *after* its value has been
> used."  Hence, the sequence of operations should be:
> 	evaluate x (value == 5)
> 	assign the computed value to x (x still == 5)
> 	increment x (x now == 6)

The language definition doesn't say, and the construct is ambiguous
(semantically ambiguous, not syntactically).  Therefore all four compilers
are correct (for this statement anyway) and the program is incorrect.

Actually I am usually quick to catch ambiguities (roughly the same as
finding counter-examples to false theorems), but never would have thought
of that second interpretation.  Yes the increment occurs after binding
the old value, but in this particular case, even I never thought of other
operations sliding in between.  It's rather astounding.

-- 

   Norman Diamond

UUCP:  {decvax|utzoo|ihnp4|allegra}!watmath!watdaisy!ndiamond
CSNET: ndiamond%watdaisy@waterloo.csnet
ARPA:  ndiamond%watdaisy%waterloo.csnet@csnet-relay.arpa

"Opinions are those of the keyboard, and do not reflect on me or higher-ups."

carl@bdaemon.UUCP (carl) (04/09/85)

Please, let us stop this discussion of side effects right NOW.  It has been
beaten to death before and is pointless.  Instead, read page 50 of K&R,
where the following sentences can be found:

"In any expression involving side effects, there can be subtle dependencies
on the order in which variables taking part in the expression are stored.
One unhappy situation is typified by the statement

	a[i] = i++;

The question is whether the subscript is the old value of i or the new.
The compiler can do this in different ways, and generate different answers
depending on its interpretation.  When side effects (assignment to actual
variables) takes place is left to the discretion of the compiler, since the
best order strongly depends on machine architecture.
	The moral of this discussion is that writing code which depends on
order of evaluation is a bad programming practice in any language."

Carl Brandauer
daemon associates, Inc.
1760 Sunset Boulevard
Boulder, CO 80302

mwm@ucbtopaz.CC.Berkeley.ARPA (04/09/85)

In article <5272@tektronix.UUCP> paulh@tektronix.UUCP (Paul Hoefling) writes:
>An inexperienced C programmer wrote a program containing the following:
>	x = x++;
>Assuming that x originally had the value 5, what should the value be after
>execution of the above expression ?

Either 5 or 6, depending on the phase of the moon and the mood of the
compiler. That expression, like such things as:

	y = funct(x, x++) ;

	y = &x ;
	x = funct((*y)++) ;

and other, cuter problems, are indeterminate. If you want your code to
be portable, you don't use such things. C is just full of goodies like
this, but so are most other languages.

	<mike

stew@harvard.ARPA (Stew Rubenstein) (04/10/85)

Regarding the question about x = x++ and a[i] = i++ and similarly
ambiguous constructs:  Why the (*@#$%^*^ can't the compiler complain
rather than flipping a coin?  Programs with statements like these are
WRONG, just as wrong as one with a missing brace.  And while I am
making suggestions to the compiler-writers out there, I'd like to
endorse the action of the compiler which warned the programmer of
a possibly unintended assignment in the statement "if (i = 0) ..."
I have spent too much time fixing bugs caused by this.  I have even
written "i == j;", also a legal statement, but one which I would
love to have had the compiler complain about.
-- 
-----------------------
Stew Rubenstein     UUCP: ihnp4!harvard!stew
Harvard Chemistry   ARPA: stew@harvard

gwyn@Brl-Vld.ARPA (VLD/VMB) (04/10/85)

A more useful question might be, "What does the draft proposed ANSI C
standard say about
	x = x++;
?"  The X3J11 committee has attempted to deal with such issues by
identifying what constitutes a "side effect" (post-increment is one)
and when side effects must be enforced during execution (at "sequence
points").  Assignment is NOT flagged as a sequence point; I don't
know whether this was intentional but I suspect it was.  The ";" of
an expression-statement causes the expression to be evaluated for its
side effects, though.

The upshot is that the result is implementation-dependent.  In general,
one is asking for trouble any time he modifies AND uses an object in
different places in the same expression, even if the behavior is
supposed to be well-defined.  I have yet to see a compiler that wouldn't
break if pushed too hard.

moroney@jon.DEC (Mike Moroney) (04/11/85)

>An inexperienced C programmer wrote a program containing the following:
>
>	x = x++;
>
>Assuming that x originally had the value 5, what should the value be after
>execution of the above expression ?

The VAX C compiler on VMS sure threw me with its answer to this one. I compiled
and ran a test program and the answer was 5.  Then I looked at the machine
code, and it didn't allocate ANYTHING for x, not even a register!

It generated the following code for the printf statement:

	pushl	#5
	pushal	$CHAR_STRING_CONSTANTS
	calls	#2,printf

  It saw through the whole mess and decided that x was 5 after the "funny"
assignment operation and didn't generate any machine code for the statement
"x = x++;"  I tried more complex programs so the compiler would not know
the value of x beforehand, and it still treated "x = x++;" as a no-op.

"There's a madness to my method."			Mike Moroney
						..decwrl!rhea!jon!moroney

gwyn@Brl-Vld.ARPA (VLD/VMB) (04/11/85)

The compiler is perfectly within its rights in making
	x = 5;
	x = x++;
result in x==5 sometimes and x==6 other times.  This
is one of the implementation-dependent aspects of the
C language, intended to allow better overall code
generation.  You should not write such source code.

If there is a
	movl	r11,r11
in your output, then you must not have invoked the C
optimizer (cc -O option).  To make code generation
easier and more reliable, the main compiler relies
on the optimizer to clean up such things.

gwyn@Brl-Vld.ARPA (VLD/VMB) (04/12/85)

At least for
	i == j;
lint issues a "null effect" message, since this is a meaningless
thing for the programmer to be doing.  Unfortunately
	if ( i = j )
is a menaingful construct that is actually widely used.  I
personally would have written
	if ( (i = j) != 0 )
but not everyone is careful to avoid the shortcuts built into C.
A "boolean" data type would have been very useful for detecting
such errors but C hasn't any, alas.

jack@boring.UUCP (04/12/85)

Hey, this is an old problem, and, moreover, one that exists
in *every* language that allows side-effects.
How about :
procedure p(var i:integer):integer;
begin
    i := i+1;
    p := i;
end (* p *);

begin
  j := i + p(i);
end.

Such constructions should *always* be avoided. 
-- 
	Jack Jansen, {decvax|philabs|seismo}!mcvax!jack
	The shell is my oyster.

alan@drivax.UUCP (Alan Fargusson) (04/12/85)

> Regarding the question about x = x++ and a[i] = i++ and similarly
> ambiguous constructs:  Why the (*@#$%^*^ can't the compiler complain

I didn't think that a[i] = i++ was ambiguous when I used it to set an
array up shuch that each element a[i] was equal to i. So call me a hacker.
The problem is that a compiler writer cannot anticipate all the errors
a user might make. There are an infinite number of correct programs, and
even more incorrect programs.
-- 

Alan Fargusson.

{ ihnp4, sftig, amdahl, ucscc, ucbvax!unisoft }!drivax!alan

ndiamond@watdaisy.UUCP (Norman Diamond) (04/13/85)

> Regarding the question about x = x++ and a[i] = i++ and similarly
> ambiguous constructs:  Why the (*@#$%^*^ can't the compiler complain
> rather than flipping a coin?

The C compiler is perfectly capable of generating code for one of the
valid meanings.  (At least some compilers are.  Some are capable of
generating invalid code, but that's beside the point.)

> Programs with statements like these are
> WRONG, just as wrong as one with a missing brace.

True.  Is lint still occasionally maintained?  Will new tests be added
as their necessity becomes apparent?

-- 

   Norman Diamond

UUCP:  {decvax|utzoo|ihnp4|allegra}!watmath!watdaisy!ndiamond
CSNET: ndiamond%watdaisy@waterloo.csnet
ARPA:  ndiamond%watdaisy%waterloo.csnet@csnet-relay.arpa

"Opinions are those of the keyboard, and do not reflect on me or higher-ups."

lspirkov@udenva.UUCP (Goldilocks) (04/15/85)

In article <> jack@boring.UUCP (Jack Jansen) writes:
>
>procedure p(var i:integer):integer;
>begin
>    p := i;
>    i := i+1;
>end (* p *);
>

you obviously don't know your pascal!  a function returns
something.  a procedure doesn't.

					Goldi

kjm@ut-ngp.UUCP (Ken Montgomery) (04/16/85)

[]

From: lspirkov@udenva.UUCP (Goldilocks)
>In article <> jack@boring.UUCP (Jack Jansen) writes:
>>
>>procedure p(var i:integer):integer;
              ^^^
>>begin
>>    p := i;
>>    i := i+1;
>>end (* p *);
>>
>
>you obviously don't know your pascal!  a function returns
>something.  a procedure doesn't.
>
>                                        Goldi

The 'var' keyword has the effect that the value of 'i' is assigned
to the corresponding actual parameter in the calling routine at the
termination of the called routine.

--
The above viewpoints are mine.  They are unrelated to
those of anyone else, including my cats and my employer.

Ken Montgomery  "Shredder-of-hapless-smurfs"
...!{ihnp4,allegra,seismo!ut-sally}!ut-ngp!kjm  [Usenet, when working]
kjm@ut-ngp.ARPA  [for Arpanauts only]

john@moncol.UUCP (John Ruschmeyer) (04/18/85)

>From: kjm@ut-ngp.UUCP (Ken Montgomery)
>Message-ID: <1617@ut-ngp.UUCP>
>
>From: lspirkov@udenva.UUCP (Goldilocks)
>>In article <> jack@boring.UUCP (Jack Jansen) writes:
>>>
>>>procedure p(var i:integer):integer;
>              ^^^
>>>begin
>>>    p := i;
>>>    i := i+1;
>>>end (* p *);
>>>
>>
>>you obviously don't know your pascal!  a function returns
>>something.  a procedure doesn't.
>>
>>                                        Goldi
>
>The 'var' keyword has the effect that the value of 'i' is assigned
>to the corresponding actual parameter in the calling routine at the
>termination of the called routine.

What goldi was referring to was this:

>procedure p(var i:integer):integer;
                           ^^^^^^^^

The part I have highlighted is used in a FUNCTION declaration to declare
the type of the value returned. The type of values returned by a PROCEDURE
is declared by the 'var' as you pointed out.

The correct declaration is:

	procedure p(var i:integer);

I don't have the original article handy, but it almost looks like someone
was trying to perform the illegal:

	function p(var i:integer):integer;

which would be an attempt at declaring a function which returns two values.
I pray that somewhere there isn't a compiler which would accept that. 
(Ooh, ick!)


-- 
Name:		John Ruschmeyer
US Mail:	Monmouth College, W. Long Branch, NJ 07764
Phone:		(201) 222-6600 x366
UUCP:		...!vax135!petsd!moncol!john	...!princeton!moncol!john
						   ...!pesnta!moncol!john
Silly Quote:
		"Ah, but what is a dream but reality without a backbone?"

lspirkov@udenva.UUCP (Goldilocks) (04/19/85)

In article <> kjm@ut-ngp.UUCP (Ken Montgomery) writes:
>[]
>
>From: lspirkov@udenva.UUCP (Goldilocks)
>>In article <> jack@boring.UUCP (Jack Jansen) writes:
>>>
>>>procedure p(var i:integer):integer;
>              ^^^
>>>begin
>>>    p := i;
>>>    i := i+1;
>>>end (* p *);
>>>
>>
>>you obviously don't know your pascal!  a function returns
>>something.  a procedure doesn't.
>>
>>                                        Goldi
>
>The 'var' keyword has the effect that the value of 'i' is assigned
>to the corresponding actual parameter in the calling routine at the
>termination of the called routine.
>
>Ken Montgomery  "Shredder-of-hapless-smurfs"

I wasn't talking about the var parameters.  i was talking
about his syntax.  try running that bit of code (with
a main program & the rest of the skeleton) and see what you
get...

					Goldi

ps:  what it should have been was:
function p(var i:integer):integer;
^^^^^^^^
	...

pps:  i got mail from someone at harvard but i couldn't
	reply straight to him.  so this is just for him:
	you're right.  i don't know my modula-2.  i
	never claimed i did.  but he specifically said pascal.

robert@gitpyr.UUCP (Robert Viduya) (04/19/85)

> 
> I don't have the original article handy, but it almost looks like someone
> was trying to perform the illegal:
> 
> 	function p(var i:integer):integer;
> 
> which would be an attempt at declaring a function which returns two values.
> I pray that somewhere there isn't a compiler which would accept that. 
> (Ooh, ick!)
> 

Wait a minute... Pascal allows you to have var parameters in functions.
There is nothing illegal about the declaration whatsoever.  All the Pascal
compilers I've used accept this.

And what's wrong with functions modifying their parameters?

		robert
-- 
Robert Viduya
Georgia Institute of Technology

...!{akgua,allegra,amd,hplabs,ihnp4,masscomp,ut-ngp}!gatech!gitpyr!robert
...!{rlgvax,sb1,uf-cgrl,unmvax,ut-sally}!gatech!gitpyr!robert

tainter@gumby.UUCP (04/22/85)

> I don't have the original article handy, but it almost looks like someone
> was trying to perform the illegal:
> 
> 	function p(var i:integer):integer;
> 
> which would be an attempt at declaring a function which returns two values.
> I pray that somewhere there isn't a compiler which would accept that. 
> (Ooh, ick!)
> 

Say what?  It is completely legal in Pascal to pass var parameters to a
function!  I PRAY all pascal compilers out there will accept this!!

-Johnathan A. Tainter


-- The views expressed are those of GOD and do not reflect on the author.

bprice@bmcg.UUCP (Bill Price) (04/26/85)

> > I don't have the original article handy, but it almost looks like someone
> > was trying to perform the illegal:
> > 	function p(var i:integer):integer;
> > I pray that somewhere there isn't a compiler which would accept that. 
> > (Ooh, ick!)
> Say what?  It is completely legal in Pascal to pass var parameters to a
> function!  I PRAY all pascal compilers out there will accept this!!
> -Johnathan A. Tainter

ANSI, IEEE, ISO, and others have published the definition of Pascal:  it's
titled, for example, "American National Standard Pascal Computer
Programming Language."  According to this definition, one of the
requirements of a Pascal compiler is that it accepts the Pascal
language--that's so obvious that it's often overlooked.  One of the
features of the Pascal language is the ability of a function to have
variable parameters.

The bottom line of that paragraph is the trivial conclusion that:

A compiler which does not accept a function declaration with a variable
parameter is not a Pascal compiler, regardless of the name of the compiler,
and regardless of any claims by the compiler writer or vendor.

"How many legs does a donkey have if you call its tail a leg?"

"One--calling a tail a leg doesn't make it one."

			--A. Lincoln


--Bill Price
-- 
--Bill Price  uucp:  {Most Anybody}!sdcsvax!bmcg!bprice
              arpa:? sdcsvax!bmcg!bprice@nosc

fjh@cord.UUCP (07/16/86)

What is the difference between:

extern	char	*A;

and

extern	char	A[];

If you do: printf("A=%s\n",A);
the first causes a core dump, the second works.

I thought pointers and arrays were equivalent?

-----
Please send me mail, if you understand this.
Thanks!

-- 

<*> Fred Hirsch <*> AT&T Bell Laboratories <*> ihnp4!cord!fjh <*>

chris@umcp-cs.UUCP (07/17/86)

In article <306@cord.UUCP> fjh@cord.UUCP (FJ Hirsch) writes:
>What is the difference between:
>
>extern	char	*A;
>
>and
>
>extern	char	A[];

Quite a bit.  The former tells the compiler that there is a variable
named `A' defined externally, and that its type is `pointer to
char'.  The latter tells it that there is a variable named `A'
defined externally, and that its type is `array of char'.  These
are most certainly *not* equivalent.  A Vax compiler, for example,
treats the former as a four-byte variable, and the latter as a
`link-time constant'.

>If you do: printf("A=%s\n",A);
>the first causes a core dump, the second works.

In that case, the actual defintion must have been

	char A[<constant>];

>I thought pointers and arrays were equivalent?

No.  This confusion seems to arise from C's convention of treating
the name of an array (in many places, but not all) as a pointer to
the first element of that array.  It is heightened by C's convention
of allowing an `array' declaration as a formal parameter:

	f(s)
		char s[];
	{
		...

It might have been better if compilers refused to accept such a
declaration, rather than silently altering it to read

		char *s;

So when *is* an object of type `array of <stuff>' treated as an
object of type `pointer to <stuff>'?  If I have not forgotten
anything, the answer is `everywhere except in sizeof and in actual
declarations'.  `extern char *A' and `extern char A[]' are actual
(not formal) declarations.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu