[comp.lang.c] C puzzle

rlkd@opusys.UUCP (R.L.K.Dattatri) (08/24/89)

Here is a small puzzle.
The program below will compile and run on some compilers but will\
not compile on others.

main()
{
	int *p;

	p = (int *) malloc(1024);
	test_it(p);
}
test_it (x)
int (*x)[];
/* If a dimension is specified all compilers will accept it */
{
	int i;

	for (i=0; i < 10; ++i)
		(*x)[i] = i;
	/* x++; */
}

The parameter 'x' in test_it without dimensions works on some compilers
but others complain incomplete array'.
I can understand that the compiler is trying to guess the size of the rows
in the array. But that should come only when the commented x++ is used.
Without the dimension all compilers generated an increment of 'int' size for
'x++' but with the dimension it was the size of dimension * int size.

Does ANSI specify anything in this regard?

|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
| Mr. R.L.K. Dattatri       (408) 446-2110 (W)     |~~~~~|                 |
| Opus Systems              (408) 243-5140 (H)     |_____|                 |
| 20863 Bldg 400                                   |\   |   |/ |~~\        |
| Stevens Creek, Cupertino                         |  \ [___|\ |   |       |
| California, 95014                                     \      |   |       |
| E-mail: {uunet,sun}!opusys!rlkd  FAX: (408) 446-5009    \    |__/        |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

chris@mimsy.UUCP (Chris Torek) (08/25/89)

In article <404@opusys.UUCP> rlkd@opusys.UUCP (R.L.K.Dattatri) writes:
>Here is a small puzzle.
>The program below will compile and run on some compilers but will
>not compile on others.

This is a big hint as to the effect that you have written an incorrect
program.  (Many compilers do not catch some forms of incorrect program.)

>main()
>{
>	int *p;
>
>	p = (int *) malloc(1024);
>	test_it(p);
>}
>test_it (x)
>int (*x)[];
>/* If a dimension is specified all compilers will accept it */
>{
>	int i;
>
>	for (i=0; i < 10; ++i)
>		(*x)[i] = i;
>	/* x++; */
>}

Here is what the 4.3BSD-tahoe lint has to say about it.

tt.c:
malloc value used inconsistently	llib-lc(288)  ::  tt.c(5)
test_it, arg. 1 used inconsistently	tt.c(11)  ::  tt.c(6)
malloc value declared inconsistently	llib-lc(288)  ::  tt.c(5)

Alas, it does not catch the declaration `int (*x)[]' itself, only
the fact that it differs from the type of p() in the call two lines
above.

>The parameter 'x' in test_it without dimensions works on some compilers
>but others complain incomplete array'.

The others are correct.  You may not elide the dimensions from []s
except in a few peculiar situations.  Here `T' stands for a simple
type or pointer, structure, or union type:

	extern T array[]; /* refers to an array of unknown size
		which must be defined elsewhere; sizeof(array) is illegal
		(many compilers give 0) */

Or

	T fn(T array[]) { ...  /* declares a pointer! */

>I can understand that the compiler is trying to guess the size of the rows
>in the array. But that should come only when the commented x++ is used.

Not necessarily: it is possible that the size and shape of a pointer to
an array depends on the size of the array.  (I have never heard of such
a machine, but one cannot rule it out offhand.)  Note that in normal C
usage, one keeps a pointer to an array element in order to get at an
array, rather than a pointer to the whole array.

>Without the dimension all compilers generated an increment of 'int' size for
>'x++' but with the dimension it was the size of dimension * int size.

I would expect more compilers to increment x by zero (4BSD PCC does).

>Does ANSI specify anything in this regard?

The proposed standard suggests that programmers not write such declarations.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

dfp@cbnewsl.ATT.COM (david.f.prosser) (08/25/89)

In article <404@opusys.UUCP> rlkd@opusys.UUCP (R.L.K.Dattatri) writes:
>Here is a small puzzle.  The program below will compile and run on some
>compilers but will not compile on others.
>
>main()
>{
>	int *p;
>	p = (int *) malloc(1024);

Since there is no visible declaration for malloc(), it must be
assumed to return an int.  Since it actually returns a void *
(equivalent in this case to char *), it is quite possible that
a "garbage" int value is consequently converted to int *.  (For
example, most 68k implementations return pointer values in a
different register than integral values.)

>	test_it(p);
>}
>test_it (x)
>int (*x)[];

A pointer to an int was passed to test_it().  This parameter
declaration is for a pointer to an unspecified-sized array of
int.  These two are not equivalent, even though the number of
indirection necessary to get to an int may be the same.

>/* If a dimension is specified all compilers will accept it */
>{
>	int i;
>	for (i=0; i < 10; ++i)
>		(*x)[i] = i;
>	/* x++; */
>}
>
>The parameter 'x' in test_it without dimensions works on some compilers
>but others complain incomplete array'.
>I can understand that the compiler is trying to guess the size of the rows
>in the array. But that should come only when the commented x++ is used.
>Without the dimension all compilers generated an increment of 'int' size for
>'x++' but with the dimension it was the size of dimension * int size.
>
>Does ANSI specify anything in this regard?

(Follow-up directed to comp.std.c.)

You are correct that the length of the array is only necessary
in this example if the "x++;" statement is included.  Pointers
to unspecified-sized arrays are valid in the pANS.

Existing implementation were of varying minds with respect to
pointers to arrays.  For example, some took a construct such as
``&array_name'' and slapped your hand with a warning stating that
the & was ignored since it was "incorrect".  This is one of the
areas where the pANS has helped the language.

Dave Prosser	...not an official X3J11 answer...

thomas@advent.uucp (06/18/91)

	The following is an interesting 'C' puzzle. 
	Consider this typical switch statement, typical except that 
	'default' is misspelled 'defalut'! What is interesting is that
	any C compiler will not and should not give you a syntax error. 
	Why?  


	switch (cmd)
	{
		case GO:
			...
			break;
		case STOP:
			...
			break;
		defalut:
			printf ("Unknown command\n");
			break;
	}

	(Hint: It is bad programming practice to jump into the 
	middle of a switch statement.)

thomas

svec5@menudo.uh.edu (T.C. Zhao) (06/20/91)

In article <4007@d75.UUCP> thomas@advent.uucp () writes:
>
>       The following is an interesting 'C' puzzle. 
>       Consider this typical switch statement, typical except that 
>       'default' is misspelled 'defalut'! What is interesting is that
>       any C compiler will not and should not give you a syntax error. 
>       Why?  
>
>
>       switch (cmd)
>       {
>              case GO:
>                     ...
>                     break;
>              case STOP:
>                     ...
>                     break;
>              defalut:
>                     printf ("Unknown command\n");
>                     break;
>       }

Well, it depends. If defalut is never referenced, some compilers
with certain switches might produce a warning: unreferenced label
or unreachable code. I have not seen any C compiler like this( it is
my impression that Fortran compiler tends to warn this kind of
unreferenced stuff), but I wish my compiler would warn.

yamada@stego.ifa.hawaii.edu (Hubert Yamada) (06/20/91)

In article <1991Jun20.010011.18425@menudo.uh.edu> svec5@menudo.uh.edu (T.C. Zhao) writes:
>In article <4007@d75.UUCP> thomas@advent.uucp () writes:
>>
>>       The following is an interesting 'C' puzzle. 
>>       Consider this typical switch statement, typical except that 
>>       'default' is misspelled 'defalut'! What is interesting is that
>>       any C compiler will not and should not give you a syntax error. 
>>       Why?  
[Example deleted]
>
>Well, it depends. If defalut is never referenced, some compilers
>with certain switches might produce a warning: unreferenced label
>or unreachable code. I have not seen any C compiler like this( it is
>my impression that Fortran compiler tends to warn this kind of
>unreferenced stuff), but I wish my compiler would warn.

Actually, I don't know of any C compiler that _won't_ tell you about
this error, if you set the warning level reasonably high.  With UNIX
cc, setting the warning level high enough == use lint.  (To avoid
flames: I'm not saying that such C compilers don't exist, or even that
they aren't common, just that none of the compilers that I use have
that problem.)

Unix gcc (1.39): gcc -Wall
	temp.c:16: warning: label `defalut' defined but not used

Sun OS 4.1 lint: lint
	temp.c(16): warning: defalut unused in function xxx 

Microsoft C 6.0: cl -WX
	temp.c(20) : warning C4102: 'defalut' : unreferenced label

PC lint (Gimpel Software): lint
	temp.c(19) : Info 744: switch statement has no default
	temp.c(20) : Warning 563: defalut (line 16) not referenced
-- 
****************************************************************************
Hubert Yamada
Internet: yamada@galileo.ifa.hawaii.edu (or yamada@uhunix.uhcc.hawaii.edu)
Bitnet: yamada@uhunix.bitnet

Dave.Harris@f14.n15.z1.fidonet.org (Dave Harris) (06/22/91)

In a message of <Jun 20 21:55>, thomas@advent.uucp (1:114/15) writes: 

 >        switch (cmd)
 >        {
...
 >                defalut:
 >                        printf ("Unknown command\n");
 >                        break;
 >        }


I glad to see I am not the only sucker that was bitten by this at one time.  
Its just another label as far as C is concerned (ie goto defalut;) 


 

--  
Uucp: ...{gatech,ames,rutgers}!ncar!asuvax!stjhmc!15!14!Dave.Harris
Internet: Dave.Harris@f14.n15.z1.fidonet.org

martin@mwtech.UUCP (Martin Weitzel) (06/22/91)

In article <13544@uhccux.uhcc.Hawaii.Edu> yamada@stego.ifa.hawaii.edu (Hubert Yamada) writes:
>In article <1991Jun20.010011.18425@menudo.uh.edu> svec5@menudo.uh.edu (T.C. Zhao) writes:
>>In article <4007@d75.UUCP> thomas@advent.uucp () writes:
>>>
>>>       The following is an interesting 'C' puzzle. 
[...]
>>
>>Well, it depends. If defalut is never referenced, some compilers
>>with certain switches might produce a warning: unreferenced label
[...]
>Actually, I don't know of any C compiler that _won't_ tell you about
>this error, if you set the warning level reasonably high.  With UNIX
>cc, setting the warning level high enough == use lint.
[...]

Using lint only works if you are in the happy situation that your
compiler (together with its header-files) is not yet so much ANSI-fied
that your lint becomes unusable. (I'm sometimes forced to use such a beast;
it's halfway down the road to ANSI-C. I like to profit from function
prototypes, but sadly enough the lint on this system is the "old" one,
which doesn't know anything of all that.)

BTW: Here's another bug with a switch statement involved, I've once been
tracing this for some hours:

	enum { RED, BLUE, GREEN } colour;
	...
	/* assign valid value to colour */
	...
	switch (colour) {
	RED:
		....; break;
	BLUE:
		....; break;
	GREEN:
		....; break;
	}

Of course, finding the bug involved isolating this piece of code and
finding out why `colour' changed its value away from one of `RED', `BLUE',
or `GREEN', which I *thought* was the reason that no branch of the switch
got ever executed ... (I confess: I didn't see the light until I had
some printf-s immediatly before and after the switch which showed the
value of `colour' in decimal and proved it beeing correct all the time.)
-- 
Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83

martin@mwtech.UUCP (Martin Weitzel) (06/22/91)

In article <4007@d75.UUCP> thomas@advent.uucp () writes:

>	The following is an interesting 'C' puzzle. 
[...]
>		defalut:
		defau1t:
Written this way ----^---- it makes the bug even more invisible on many
terminal screens and printouts ... :-)
-- 
Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83

yamada@stego.ifa.hawaii.edu (Hubert Yamada) (06/25/91)

[This quote been edited to shorten it]
In article <1173@mwtech.UUCP> martin@mwtech.UUCP (Martin Weitzel) writes:
>In article <13544@uhccux.uhcc.Hawaii.Edu> yamada@stego.ifa.hawaii.edu (Hubert Yamada) writes:
>>Actually, I don't know of any C compiler that _won't_ tell you about
>>this error, if you set the warning level reasonably high.  With UNIX
>>cc, setting the warning level high enough == use lint.
>
>Using lint only works if you are in the happy situation that your
>compiler (together with its header-files) is not yet so much ANSI-fied
>that your lint becomes unusable. (I'm sometimes forced to use such a beast;
>it's halfway down the road to ANSI-C. I like to profit from function
>prototypes, but sadly enough the lint on this system is the "old" one,
>which doesn't know anything of all that.)

This is _so_ true.  Fortunately, the ansi compilers that I've dealt
with had better local error checking than cc.  But I haven't found any
compiler that does global error detection as well as lint does.  I've
taken the approach of writing code that compiles correctly under ansi C
compilers and under traditional C compilers.  In order to do this I've
been forced to use some macros that modify declarations and prototypes
depending on the type of compiler is.  This lets me have the advantage
of both.  But the macros are ugly and clumsy, and the resultant code is
_very_ugly_.
-- 
****************************************************************************
Hubert Yamada
Internet: yamada@galileo.ifa.hawaii.edu (or yamada@uhunix.uhcc.hawaii.edu)
Bitnet: yamada@uhunix.bitnet

mcdaniel@adi.com (Tim McDaniel) (06/25/91)

In article <1173@mwtech.UUCP> martin@mwtech.UUCP (Martin Weitzel) writes:

   Using lint only works if you are in the happy situation that your
   compiler (together with its header-files) is not yet so much
   ANSI-fied that your lint becomes unusable.

At this point, I will put in my monthly plug for FlexeLint/PC-Lint
from Gimpel Software.   (Disclaimer: I'm just a satisfied customer; I
have no financial or other interest in Gimpel Software, except for
wanting future releases.  8-)

Gimpel Software's FlexeLint is fully ANSI-compatable.  It can also
handle most pre-ANSI constructs and semantics.  It is an excellent
product, primarily because each message can be individually turned on
or off, within parts of a source file or for particular symbols or
files.

	Gimpel Software
	3207 Hogarth lane
	Collegeville, PA  19426
	telephone: 1 215 584 4261

It can be run on SUNs, VAXen, PCs (PC-Lint), et cetera.

--
  "Of course he has a knife; he always has a knife.  We all have knives.
  It's 1183 and we're barbarians." -- Eleanor of Aquitaine, "A Lion in Winter"
Tim McDaniel                 Applied Dynamics Int'l.; Ann Arbor, Michigan, USA
Internet: mcdaniel@adi.com                UUCP: {uunet,sharkey}!amara!mcdaniel

chaplin@keinstr.uucp (chaplin) (06/26/91)

In article <4007@d75.UUCP> thomas@advent.uucp () writes:
>
>	The following is an interesting 'C' puzzle. 
>	Consider this typical switch statement, typical except that 
>	'default' is misspelled 'defalut'! What is interesting is that
>	any C compiler will not and should not give you a syntax error. 
>	Why?  
>
>
>	switch (cmd)
>	{
>		case GO:
>			...
>			break;
>		case STOP:
>			...
>			break;
>		defalut:
        ^^^^^^^^
This is a valid statement label, useful as the target of a goto statement.
_K&R_ 2nd Edition page 66.
>			printf ("Unknown command\n");
>			break;
>	}
>
>	(Hint: It is bad programming practice to jump into the 
>	middle of a switch statement.)
>
>thomas

That was almost too easy.  BTW, according to _K&R_ it is bad programming
practice in almost all cases to use goto, and since the *only* use of a label
is as the target of the goto statement (_K&R_ 2nd ed. page 222), labels are
almost always bad programming practice.

You did not intend this as a label though.  Hmmm... an interesting problem.
I'm not sure how much help lint would be, but I do know that Saber C would
detect this as a label defined but never referenced.

-- 
Roger Chaplin / Instruments Division Engineering / "Though I'd been lost now I
chaplin@keinstr.uucp / CI$: 76307,3506          / felt I was found when He
#include <disclaimer.h>                        / looked at me with His
#include "disclaimer.h" /* cover all bases */ / forgiving eyes." - Michael Card