[net.lang.c] type cast in initializer

stevens@hsi.UUCP (01/29/86)

I've found the two lines

	int	x = 0;
	char	*ptr = (char *) &x;

acceptable to every C compiler I've used, until running into the
Whitesmith's C compiler.  They refuse to accept the type coercion "(char *)"
on the second initialization.  As I read K&R this should be acceptable
through the rules

	initializer:
		= expression			(Sec. 8.6)

	expression:
		( type-name ) expression	(Sec. 7.2)

I talked to Whitesmiths about this and they are firm that their
interpretation of the "standard" is that a type coercion following the
equals sign is not allowed and they don't plan to change their compiler.

Am I missing something ??  What does the proposed ANSI standard have
to say about this ??

	Richard Stevens
	Health Systems International, New Haven, CT
           ihnp4 ! hsi ! stevens

chris@umcp-cs.UUCP (Chris Torek) (01/30/86)

In article <302@hsi.UUCP> stevens@hsi.UUCP (Richard Stevens) writes:

> I've found the two lines
>	int	x = 0;
>	char	*ptr = (char *) &x;
> acceptable to every C compiler I've used, until running into the
> Whitesmith's C compiler.  They refuse to accept the type coercion
> "(char *)" on the second initialization. ...
>
> I talked to Whitesmiths about this and they are firm that their
> interpretation of the "standard" is that a type coercion following
> the equals sign is not allowed and they don't plan to change their
> compiler.

Whitesmiths has never been one to do reasonable things with their
compiler.  Their interpretation is bogus.  How a company can be
so simultaneously good and bad at what they do is just amazing.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1415)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu

keesan@bbncc5.UUCP (Morris M. Keesan) (01/31/86)

In article <302@hsi.UUCP> stevens@hsi.UUCP (Richard Stevens) writes:
>I've found the two lines
>
>	int	x = 0;
>	char	*ptr = (char *) &x;
>
>acceptable to every C compiler I've used, until running into the
>Whitesmith's C compiler.  They refuse to accept the type coercion "(char *)"
>on the second initialization.  As I read K&R this should be acceptable
>through the rules
>
>	initializer:
>		= expression			(Sec. 8.6)
>
>	expression:
>		( type-name ) expression	(Sec. 7.2)
>
>I talked to Whitesmiths about this and they are firm that their
>interpretation of the "standard" is that a type coercion following the
>equals sign is not allowed and they don't plan to change their compiler.

    My interpretation agrees with yours.  Whitesmith are going by section 15,
which enumerates the operators which are allowed in a constant expression,
type-casting not being one of them.  They are missing the additional information
in paragraph 2 of 8.6, which increases the sorts of expression allowed, in
particular allowing automatic variables to be initialized by "arbitrary
expressions involving constants, and previously declared variables and
functions."  

    In any case, I'm not sure why you'd want to do what your example does,
since the cast here is a no-op.  
-- 
Morris M. Keesan
keesan@bbn-unix.ARPA
{decvax,ihnp4,etc.}!bbncca!keesan

art@acc.arpa (02/01/86)

 
> I've found the two lines
> 
> 	int	x = 0;
> 	char	*ptr = (char *) &x;
> 
> acceptable to every C compiler I've used, until running into the
> Whitesmith's C compiler.  They refuse to accept the type coercion "(char *)"
> on the second initialization.  As I read K&R this should be acceptable
> through the rules

The posting did not indicate whether the variables are static or auto.

The initializer should be legal if x is static, but not neccesarily if
x is declared as an auto.  If x is auto, the compiler could place it in
a register whose address cannot be taken.

The compiler should be smart enough to notice the address operator and
disallow register allocation.  K&R only states that variables declared
register cannot have their address taken.  Anyone know what ANSI says?

------

jsdy@hadron.UUCP (Joseph S. D. Yao) (02/01/86)

In article <1450@bbncc5.UUCP> keesan@bbncc5.UUCP (Morris M. Keesan) writes:
>In article <302@hsi.UUCP> stevens@hsi.UUCP (Richard Stevens) writes:
>>	int	x = 0;
>>	char	*ptr = (char *) &x;
>    In any case, I'm not sure why you'd want to do what your example does,
>since the cast here is a no-op.  

Two reasons are immediately obvious.  The less compelling is that
lint tells you to.  The more compelling is that on some computer
architectures, e.g. one with type-tagged pointers, the cast may
[ NOTE:  n o t  "will", just "may" ] not be a no-op.  Some compilers
will even reject the un-cast initialisation out of hand.

Come to think of it, the 'lint' reason is not less compelling.
Since you are doing something "unnatural" -- pointing to an object
of one type with a pointer of another type -- this falls under the
heading of explicitly having to say, "yes, this is not an error, I
do mean to do exactly what this says."
-- 

	Joe Yao		hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (02/02/86)

> > I've found the two lines
> > 
> > 	int	x = 0;
> > 	char	*ptr = (char *) &x;
> > 
> > acceptable to every C compiler I've used, until running into the
> > Whitesmith's C compiler.  They refuse to accept the type coercion "(char *)"
> > on the second initialization.  As I read K&R this should be acceptable
> > through the rules
> 
> The posting did not indicate whether the variables are static or auto.

The variables cannot be static, with those declarations.  I assume you
mean, file scope vs. block scope.  In any case, it doesn't matter; the
example is valid C code.  (However, I wonder what it was trying to do.
Treating the address of an int as a (char *) is rarely required, with
fread/fwrite buffer parameter being the only common occurrence.)

> The initializer should be legal if x is static, but not neccesarily if
> x is declared as an auto.  If x is auto, the compiler could place it in
> a register whose address cannot be taken.

That would be a compiler bug.  Also, the presence or absence of the type
cast would surely be irrelevant in such a case.

> The compiler should be smart enough to notice the address operator and
> disallow register allocation.  K&R only states that variables declared
> register cannot have their address taken.  Anyone know what ANSI says?

"The operand of the unary & operator must be a function locator or an
lvalue that designates an object other than a bit-field or an object
declared with the `register' storage-class specifier."

chris@umcp-cs.UUCP (Chris Torek) (02/02/86)

In article <2124@brl-tgr.ARPA> art@acc.arpa writes:
> The initializer [for
>	int x = 0; char *ptr = (char *) &x;
> ] should be legal if x is static, but not necessarily if x is
> declared as an auto.  If x is auto, the compiler could place it in
> a register whose address cannot be taken.

The compiler can only do this if (1) it can take the address of a
register (a la Pyramid) or (2) it has determined that nowhere is
the address actually taken.  The compiler MUST NOT make `&var'
illegal when `var' was not declared `register'.  Another way to
look at this is that `register' is not really a `hint to the
compiler' about using a machine register, but rather a `promise to
the compiler' that the programmer will not take the address of the
variable.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1415)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu

hrp@cray.UUCP (Hal Peterson) (02/03/86)

> >	int	x = 0;
> >	char	*ptr = (char *) &x;
> 
>     In any case, I'm not sure why you'd want to do what your example does,
> since the cast here is a no-op.  

An int pointer does not necessarily have the same format as a char pointer.
Consider a word addressible machine on which the char's are packed into the
words.
-- 
Hal Peterson / Cray Research / 1440 Northland Dr. / Mendota Hts, MN  55120
	UUCP:  ihnp4!cray!hrp		phone:  (612) 681-3085

gwyn@brl-smoke.ARPA (Doug Gwyn ) (02/07/86)

>> >	int	x = 0;
>> >	char	*ptr = (char *) &x;
>> 
>>     In any case, I'm not sure why you'd want to do what your example does,
>> since the cast here is a no-op.  
>
>An int pointer does not necessarily have the same format as a char pointer.
>Consider a word addressible machine on which the char's are packed into the
>words.

But, the = forces the same type coercion as the type cast.
Writing the cast explicitly is good style, however.
I don't see why the fellow wants to do what he's doing
quite apart from the question of how to express it..

ansok@spp3.UUCP (Gary Ansok) (02/08/86)

>	int	x = 0;
>	char	*ptr = (char *) &x;

Even if the pointers (int *) and (char *) have different formats,
the assignment should take care of the conversion, so the cast should
be unnecessary.  A cast in an assignment var_1 = (type) var_2 is never
strictly necessary, except for readability (a good reason!), to keep
lint happy, or to work around bad compilers.  (The cast *should* be
acceptable to the compiler, though).  As I understand it, a cast has
the effect of an assignment to a temporary unnamed variable;
sqrt((double) i) is equivalent to (tmp_double = i, sqrt(tmp_double)).

Are there any other cases where casts are NEEDED besides:

	function calls:  doub_var = sqrt((double) int_var);
	pointer punning: long_var = *(long *) char_ptr;

Note: that last example is NONportable and downright dangerous
on machines with alignment requirements.  Still, it gets used
by a lot of programmers (including me, on occasion...sigh).

			Gary Ansok
			{ihnp4,ucbvax,decvax}!trwrb!trwspp!spp3!ansok

msb@lsuc.UUCP (Mark Brader) (02/08/86)

In regard to...
> > >	int	x = 0;
> > >	char	*ptr = (char *) &x;

> >    In any case, I'm not sure why you'd want to do what your example does,
> >since the cast here is a no-op.  

Joseph S. D. Yao responds...
> Two reasons are immediately obvious...

and goes on to give three reasons.  Two are excellent, but the other is wrong:

> ... on some computer
> architectures, e.g. one with type-tagged pointers, the cast may
> [ NOTE:  n o t  "will", just "may" ] not be a no-op.

If this is not a slip, it stems from a misconception of casting which
is a Frequently Repeated Error in this newsgroup.  (If I remember what
somebody posted a while ago, the error found its way into a DECUS C
manual, which accounts for its widespreadness.)

The cast specifies a conversion.  If TTT and UUU are types, and
we have:
	TTT t; UUU u; /* ..... */ t = u;

then at that point the expressions t and (TTT)u are interchangeable.
In the case of type-tagged pointers, the cast specifies that the
pointer tagged "int" is to be converted to one tagged "char" and
stored in the variable, but so would the initialization or assignment
without the cast, if the compiler accepts it at all.

Mark Brader
[ The current ANSI draft C standard states:
  Preceding an expression by a parenthesized type name
  c o n v e r t s    t h e    v a l u e		[ emphasis mine]
  of the expression to the named type.  This construction is called a cast.]

throopw@dg_rtp.UUCP (02/09/86)

[ The case under discussion:
        int     x = 0;
        char    *ptr = (char *) &x;
]

[keesan@bbncc5.UUCP]
> >    In any case, I'm not sure why you'd want to do what your example does,
> >since the cast here is a no-op.

[hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}]
> Two reasons are immediately obvious.  The less compelling is that
> lint tells you to.  The more compelling is that on some computer
> architectures, e.g. one with type-tagged pointers, the cast may
> [ NOTE:  n o t  "will", just "may" ] not be a no-op.  Some compilers
> will even reject the un-cast initialisation out of hand.

Acutally, for K&R C, Keesan is correct.  I was about to post just about
what Yao posted, but I looked it up in K&R, and found two interesting
points, the first about casts, and the second about initializations.

    [from The Book, page 42, paragraph 3, line 5, read in the style of
          a Gregorian chant for best effect]
    The precise meaning of a cast is in fact as if *expression* were
    assigned to a variable of the specified type, which is then used in
    place of the whole construction.

    [from The Book, page 198, paragraph 5]
    When an initializer applies to a *scalar* (a pointer or an object of
    arithmetic type), it consists of a single expression, perhaps in
    braces.  The initial value of the object is taken from the
    expression; the same conversions as for assignment are performed.

I'm not sure what ANSI says about it, but it's probably something
similar.

So, casts are equivalent to assignment, and initialization (for scalars)
is equivalent to assignment, therefore initialization is equivalent to a
cast, and the explicit cast is redundant.  But I'd still put it in,
myself, since

> Come to think of it, the 'lint' reason is not less compelling.

is right on the money... if you are doing something perverse like this
with types, you had better justify yourself to lint (or some other
typechecker).  If you don't lint your code and pay attention to what
lint says, you are just coding in a peculiar assembly language.
-- 
Wayne Throop at Data General, RTP, NC
<the-known-world>!mcnc!rti-sel!dg_rtp!throopw

gwyn@brl-smoke.ARPA (Doug Gwyn ) (02/10/86)

In article <269@spp3.UUCP> ansok@spp3.UUCP (Gary Ansok) asks:

> Are there any other cases where casts are NEEDED besides:
>
>	function calls:  doub_var = sqrt((double) int_var);
>	pointer punning: long_var = *(long *) char_ptr;

Type casts are also useful in expressions, to avoid introducing
a temporary variable just to accomplish a type conversion.  One
example is casting a (char) to an (unsigned char) before putting
it into an (int) variable, to prevent sign-extension.  Another
is casting a (long) to an (unsigned long) before a right-shift,
to avoid sign-propagation.  A third case is converting an (int)
to a (long) early in an integer expression, to ensure that the
operations will not overflow.

But it is true that type casts should be used sparingly, and
never to compensate for sloppiness in declaring data types.

C note of the day: 'x' is of type (int), not (char).

jsdy@hadron.UUCP (Joseph S. D. Yao) (02/10/86)

In article <1100@lsuc.UUCP> msb@lsuc.UUCP (Mark Brader) writes:
>In regard to...
>> > >	int	x = 0;
>> > >	char	*ptr = (char *) &x;
>> >    In any case, I'm not sure why you'd want to do what your example does,
>> >since the cast here is a no-op.  
>Joseph S. D. Yao responds...
>> Two reasons are immediately obvious...
>
>and goes on to give three reasons.  Two are excellent, but the other is wrong:
>> ... on some computer
>> architectures, e.g. one with type-tagged pointers, the cast may
>> [ NOTE:  n o t  "will", just "may" ] not be a no-op.

(and this was the non-obvious, third reason.)

>If this is not a slip, it stems from a misconception of casting which
>is a Frequently Repeated Error in this newsgroup.  ...
>The cast specifies a conversion.  ...
>In the case of type-tagged pointers, the cast specifies that the
>pointer tagged "int" is to be converted to one tagged "char" and
>stored in the variable, but so would the initialization or assignment
>without the cast, if the compiler accepts it at all.

Perhaps this is my mistake, but I don't see what you have said that
differs from mine.  Yes, it specifies a conversion (if necessary).
Therefore the cast may possibly not be a no-op.  As you note, to
even compile with some compilers, it may be required.  Even if it
is not required, however, then it is implicit and (possibly) not a
no-op.  The fact that it is required to be explicit on some machines
and not cared about on others implies that you should use it if you
desire that your code be more "portable".  Does this explain why I
say that it may not be a no-op?
-- 

	Joe Yao		hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}

nather@utastro.UUCP (Ed Nather) (02/11/86)

In article <792@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn ) writes:

> C note of the day: 'x' is of type (int), not (char).

*sigh*  -- thanks, Doug.  I just found that out yesterday, the hard way.
The values of '\377' and -1 are one and the same without a type cast.
Now, if I'd just read the news, instead of debugging ...
-- 
Ed Nather
Astronomy Dept, U of Texas @ Austin
{allegra,ihnp4}!{noao,ut-sally}!utastro!nather
nather@astro.UTEXAS.EDU

chris@umcp-cs.UUCP (Chris Torek) (02/12/86)

In article <354@utastro.UUCP> nather@utastro.UUCP (Ed Nather) writes:
>In article <792@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn) writes:
>> C note of the day: 'x' is of type (int), not (char).
>The values of '\377' and -1 are one and the same without a type cast.

Yes---*if* your machine has signed `char's.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1415)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu

rb@ccivax.UUCP (rex ballard) (02/12/86)

In article <269@spp3.UUCP> ansok@spp3.UUCP (Gary Ansok) writes:
>
>Are there any other cases where casts are NEEDED besides:
>
>	function calls:  doub_var = sqrt((double) int_var);
>	pointer punning: long_var = *(long *) char_ptr;
>
	Yes, accessing members of structures.
	ie:
	struct x y;
	struct i j;
	i.memb=y.memb;  /* some compilers hate this */
	should be written:
	i.memb= ((struct i)x).memb;

	this is especially true if both structures contain 'memb' but
	'memb' is different type or placement.
	A union is probably preferred.

	

gwyn@brl-smoke.ARPA (Doug Gwyn ) (02/14/86)

>The values of '\377' and -1 are one and the same without a type cast.

Well, on some architectures they are and on some they aren't.
X3J11 appears to have decided that they are the same whenever
a plain (char) is treated as (signed char); otherwise '\377'
has the value 255.  I don't like this, but I suspect it's in
the rules for "historical reasons".

gwyn@brl-smoke.ARPA (Doug Gwyn ) (02/16/86)

In article <392@ccivax.UUCP> rb@ccivax.UUCP (What's in a name ?) writes:
>In article <269@spp3.UUCP> ansok@spp3.UUCP (Gary Ansok) writes:
>>
>>Are there any other cases where casts are NEEDED besides:
>>
>>	function calls:  doub_var = sqrt((double) int_var);
>>	pointer punning: long_var = *(long *) char_ptr;
>>
>	Yes, accessing members of structures.
>	ie:
>	struct x y;
>	struct i j;
>	i.memb=y.memb;  /* some compilers hate this */
>	should be written:
>	i.memb= ((struct i)x).memb;
>
>	this is especially true if both structures contain 'memb' but
>	'memb' is different type or placement.
>	A union is probably preferred.

For the benefit of C novices:
The above is nonsense; don't pay attention to it.

dan@BBN-PROPHET.ARPA (Dan Franklin) (02/18/86)

In article <3154@umcp-cs.UUCP> Chris Torek writes:

> In article <354@utastro.UUCP> nather@utastro.UUCP (Ed Nather) writes:

> >In article <792@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn) writes:
> >The values of '\377' and -1 are one and the same without a type cast.

> Yes---*if* your machine has signed `char's.

AND if your machine has eight-bit bytes...

	Dan Franklin

gwyn@brl-smoke.ARPA (Doug Gwyn ) (02/19/86)

In article <1058@brl-smoke.ARPA> Dan Franklin <dan@BBN-PROPHET.ARPA> writes:
>In article <3154@umcp-cs.UUCP> Chris Torek writes:
>> In article <354@utastro.UUCP> nather@utastro.UUCP (Ed Nather) writes:
>> >In article <792@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn) writes:
>> >The values of '\377' and -1 are one and the same without a type cast.

PLEASE fix the attributions when you post things.
The above sequence makes it appear as if I said
the attributed statement.  Actually, if one looks
really hard, he may discover that the attribution
with my name in it should have been totally omitted.

No big deal, but with silly software like this,
people have to assume responsibility for clarity.

greg@utcsri.UUCP (Gregory Smith) (02/25/86)

>> >The values of '\377' and -1 are one and the same without a type cast.

I have lost of track of who originally said that, but it is presented as
evidence that '\377' ( or any char constant, e.g. 'x' ) is of type (int),
not of type (char). This is not evidence though, since
	int x;   x = 'a';
will convert 'a' to (int) if it was not already, before assigning. This
includes sign extending if that is the convention on your system. The same
applies to   func('x') and  case '\300':. Thus the equality between
-1 and '\377' does not mean that they are both int's. The only way to tell
is to do a sizeof('x'), which is 1 if 'x' is (char) and 2 or 4 or .. if 'x'
is int.
Having said this, I will add that char constants are in fact of type (int),
which can be verified by the above test. ( I speak for 4.2BSD).

Greg Smith
University of Toronto