casting

D

Dann Corbit

Christian Christmann said:
Hi,

a question on castings.

My code example:

#include <stdio.h>

int main( void )
{
unsigned int a = 4294967295U;
signed int b = 4294967295U;
signed int c = (signed int) a;

printf( "a:%ud\n", a );
printf( "b:%ud\n", b );
printf( "c:%ud\n", c );

return 0;
}



The output is:
a:4294967295d
b:4294967295d
c:4294967295d

I don't understand why "b" and "c" are also a 32-bit values. Since I
defined "b" and "c" as signed int, there are ony 31 bits that can be used
to represent the number, thus the value range is [-2147483648,
2147483647].
When assigning "b" the value 4294967295U, I thought that an implicit cast
is performed that converts the value to a 31bit value + 1 bit for the
sign.
In a similar way, "c = (signed int)a" is an explicit cast that should
convert the 32bit value of "a" into a 31bit value represented by "c".
However, printf indicates that casting is not performed. Why?

A cast just means to reinterpret the value as another type. I think in this
case it is not doing what you think it ought to do, but it is doing what it
is supposed to do.

You would probably find :
signed int d = -1;
unsigned int e = -1;
....
printf( "d:%ud\n", d );

printf( "e:%ud\n", e );

equally surprising.

Have a look at this:
http://en.wikipedia.org/wiki/Two's_complement
http://www.azillionmonkeys.com/qed/2scomp.html
http://www.hal-pc.org/~clyndes/computer-arithmetic/twoscomplement.html
 
R

Richard Heathfield

Christian Christmann said:
Hi,

a question on castings.

My code example:

#include <stdio.h>

int main( void )
{
unsigned int a = 4294967295U;
signed int b = 4294967295U;
signed int c = (signed int) a;

printf( "a:%ud\n", a );
printf( "b:%ud\n", b );
printf( "c:%ud\n", c );

return 0;
}



The output is:
a:4294967295d
b:4294967295d
c:4294967295d

I don't understand why "b" and "c" are also a 32-bit values.

C doesn't guarantee that they are.
Since I
defined "b" and "c" as signed int, there are ony 31 bits that can be used
to represent the number,

Again, C doesn't guarantee this.
thus the value range is [-2147483648, 2147483647].

Nor this.
When assigning "b" the value 4294967295U, I thought that an
implicit cast

No such thing. A cast is an explicit conversion.
is performed that converts the value to a 31bit value + 1
bit for the sign.

C doesn't guarantee this.
In a similar way, "c = (signed int)a" is an explicit
cast

And as I write this it is now 8:38 A.M. (GMT) in the morning of the
forenoon, courtesy of the Department of Redundancy Department.
that should convert the 32bit value of "a" into a 31bit value
represented by "c". However, printf indicates that casting is not
performed. Why?

printf indicates nothing of the kind. All it indicates is that you have not
yet got around to reading page 244 of K&R.
 
K

Keith Thompson

Dann Corbit said:
A cast just means to reinterpret the value as another type.

No, a cast is an operator that performs a type conversion. In some
cases, the conversion might have the same effect as reinterpreting the
bits of the source expression as if they represented a value of the
target type, but that's not how it's defined. (Consider (int)3.14 or
(double)42, for example.)
 
K

Keith Thompson

Christian Christmann said:
a question on castings.

My code example:

Your code assumes that int and unsigned int are 32 bits (something not
guaranteed by the language).
#include <stdio.h>

int main( void )
{
unsigned int a = 4294967295U;
signed int b = 4294967295U;

The value 4294967295U is implicitly converted from unsigned int to
signed int. Since the value cannot be represented in the target type,
the conversion yields an implementation-defined result (or raises an
implementation-defined signal, but we can ignore that possibility).

On most implementations, the conversion will yield the value -1.
signed int c = (signed int) a;

This is the same as above, except that the conversion is explicit.
printf( "a:%ud\n", a );
printf( "b:%ud\n", b );
printf( "c:%ud\n", c );

Use "%d" for int, "%u" for unsigned int. In "%ud", the "%u" prints an
unsigned int, and the "d" prints a letter 'd'.
return 0;
}



The output is:
a:4294967295d
b:4294967295d
c:4294967295d

I don't understand why "b" and "c" are also a 32-bit values. Since I
defined "b" and "c" as signed int, there are ony 31 bits that can be used
to represent the number, thus the value range is [-2147483648, 2147483647].

You lied to the printf() function. The "%u" format expects an
unsigned int; you gave it a signed int. I think the standard happens
to guarantee that this will work for values that are within the range
of both signed int and unsigned int, but you're passing passing a
value of -1. I'm fairly sure this invokes undefined behavior (it's at
least implementation-specific).

Most likely the value -1 is represented in two's-complement as 32 1
bits, a sign bit followed by 31 value bits. printf() interprets this
as an unsigned value with the same representation, namely 4294967295
(0xffffffff). If you used the correct format "%d", for the signed
values, the output would be:

a:4294967295d
b:-1
c:-1
When assigning "b" the value 4294967295U, I thought that an implicit cast
is performed that converts the value to a 31bit value + 1 bit for the sign.

There is no such thing as an "implicit cast". A cast is an explicit
operator that performs a conversion. There are implicit conversions,
as I mentioned above. In this case, the implicit conversion happens
to convert the unsigned value 4294967295U to the signed value -1.
In a similar way, "c = (signed int)a" is an explicit cast that should
convert the 32bit value of "a" into a 31bit value represented by "c".
However, printf indicates that casting is not performed. Why?

If the printf were correct, it would show a value of -1. But again,
this particular result for the conversion is very common, but it's
implementation-specific.
 
C

CBFalconer

Christian said:
a question on castings.

My code example:

#include <stdio.h>

int main( void )
{
unsigned int a = 4294967295U;
signed int b = 4294967295U;
signed int c = (signed int) a;

printf( "a:%ud\n", a );
printf( "b:%ud\n", b );
printf( "c:%ud\n", c );

return 0;
}

The output is:
a:4294967295d
b:4294967295d
c:4294967295d

I don't understand why "b" and "c" are also a 32-bit values.
.... snip ...

Trying to stuff a value into a signed object that cannot hold that
value results in implementation defined behaviour. You could have
just set off that 3 tons of fertilizer they found in Canada. Only
stuffing into unsigned objects has a defined action.

--
"Our enemies are innovative and resourceful, and so are we.
They never stop thinking about new ways to harm our country
and our people, and neither do we." -- G. W. Bush.
"The people can always be brought to the bidding of the
leaders. All you have to do is tell them they are being
attacked and denounce the pacifists for lack of patriotism
and exposing the country to danger. It works the same way
in any country." --Hermann Goering.
 
C

Christian Christmann

Hi,

a question on castings.

My code example:

#include <stdio.h>

int main( void )
{
unsigned int a = 4294967295U;
signed int b = 4294967295U;
signed int c = (signed int) a;

printf( "a:%ud\n", a );
printf( "b:%ud\n", b );
printf( "c:%ud\n", c );

return 0;
}



The output is:
a:4294967295d
b:4294967295d
c:4294967295d

I don't understand why "b" and "c" are also a 32-bit values. Since I
defined "b" and "c" as signed int, there are ony 31 bits that can be used
to represent the number, thus the value range is [-2147483648, 2147483647].
When assigning "b" the value 4294967295U, I thought that an implicit cast
is performed that converts the value to a 31bit value + 1 bit for the sign.
In a similar way, "c = (signed int)a" is an explicit cast that should
convert the 32bit value of "a" into a 31bit value represented by "c".
However, printf indicates that casting is not performed. Why?

Regards,
Chris
 
K

Keith Thompson

CBFalconer said:
Trying to stuff a value into a signed object that cannot hold that
value results in implementation defined behaviour. You could have
just set off that 3 tons of fertilizer they found in Canada. Only
stuffing into unsigned objects has a defined action.

On a conversion to a signed integer type, if the value cannot be
represented, "either the result is implementation-defined or an
implementation-defined signal is raised". There is no undefined
behavior.
 
C

CBFalconer

Keith said:
On a conversion to a signed integer type, if the value cannot be
represented, "either the result is implementation-defined or an
implementation-defined signal is raised". There is no undefined
behavior.

Doesn't the phrase "implementation defined behaviour" mean just
that? To me, that includes signalling or peculiar result values.

--
Some informative links:
http://www.geocities.com/nnqweb/
http://www.catb.org/~esr/faqs/smart-questions.html
http://www.caliburn.nl/topposting.html
http://www.netmeister.org/news/learn2quote.html
 
J

jaysome

Doesn't the phrase "implementation defined behaviour" mean just
that? To me, that includes signalling or peculiar result values.

So what you're saying is that the consequences of "implementation
defined behaviour" could be the same as the consequences of "undefined
behaviour"?

If that were the case, and I'm not saying that it is or isn't,
shouldn't we expect some hard-core pedantics to start telling us that
use of "implementation defined behaviou" could lead to formatting of
our hard drives?

Personally, I could see going with your way of thinking, and thusly I
proclaim these two universal truths about those who have programmed in
C:

The probability of you committing undefined bahavior is greater than
50%. Note that it's "greater than" and not "greater than or equal to.

The probability of you committing undefined bahavior that results in
formatting of your hard drive is less than 50%. Note that it's "less
than" and not "less than or equal to".

Regards
 
R

Richard Heathfield

jaysome said:

So what you're saying is that the consequences of "implementation
defined behaviour" could be the same as the consequences of "undefined
behaviour"?

If that were the case, and I'm not saying that it is or isn't,
shouldn't we expect some hard-core pedantics to start telling us that
use of "implementation defined behaviou" could lead to formatting of
our hard drives?

It *can*. And in some cases it does.

The difference is that, for implementation-defined behaviour, the
implementation is required to *document* this effect. If you want to format
your drive, such a feature can be extremely useful, n'est-ce-pas?
 
J

jaysome

jaysome said:



It *can*. And in some cases it does.

The difference is that, for implementation-defined behaviour, the
implementation is required to *document* this effect. If you want to format
your drive, such a feature can be extremely useful, n'est-ce-pas?

But it still leaves me uneasy about investing in
HowToEasilyFormatYourHardDrive.com. I've lost a lot of money on other
ventures, so maybe I'll take your advice on this one. Put me down for
$500.00.
 
K

Keith Thompson

CBFalconer said:
Doesn't the phrase "implementation defined behaviour" mean just
that? To me, that includes signalling or peculiar result values.

Yes, it's implementation-defined behavior, *not* undefined behavior.
The implementation has to document what it does, but it must choose
from the options specified by the standard. Setting off bombs or
causing nasal demons are not allowed.
 
K

Keith Thompson

Richard Heathfield said:
jaysome said:



It *can*. And in some cases it does.

The difference is that, for implementation-defined behaviour, the
implementation is required to *document* this effect. If you want to format
your drive, such a feature can be extremely useful, n'est-ce-pas?

The other difference is that, in the case of implementation-defined
behavior, the standard provides two or more possibilities and the
implementation has to pick one of them. (Unspecified behavior is the
same, except that the implementation needn't document its choice.)

These terms are all defined in section 3 of the standard.
 
R

Richard Heathfield

Keith Thompson said:
The other difference is that, in the case of implementation-defined
behavior, the standard provides two or more possibilities and the
implementation has to pick one of them. (Unspecified behavior is the
same, except that the implementation needn't document its choice.)

Well, yes, you're right - but because you're right, it is clear that the C99
Standard is broken (again). I'm thinking of alternative forms of main()
other than the two defined by the Standard. The Standard says that main()
may be defined "in some other implementation-defined manner" but, as far as
I can tell, no alternative possibilities are described. So the implementor
who wishes to provide an alternative main() interface has zero alternatives
from which to choose.
 
R

Richard Bos

Keith Thompson said:
On a conversion to a signed integer type, if the value cannot be
represented, "either the result is implementation-defined or an
implementation-defined signal is raised". There is no undefined
behavior.

However, in the cases where the I-D signal is raised, the Standard does
not completely define what the outcome of this signal is; indeed, in
those cases where the startup handler for this signal is SIG_IGN (which
returns as if nothing has happened), the behaviour is explicitly
undefined by 7.14.1.1#3.

Richard
 
O

Old Wolf

Keith said:
The other difference is that, in the case of implementation-defined
behavior, the standard provides two or more possibilities and the
implementation has to pick one of them.

What are the two or more possibilities for an out-of-range
assignment?
 
R

Richard Heathfield

Old Wolf said:
What are the two or more possibilities for an out-of-range
assignment?

That doesn't smell like "implementation-defined" to me, but for the sake of
a quiet life and not having to look it up, I'll assume you're right (for
the purposes of this discussion at least). Given all that, and in the
absence of any other information to the contrary, I would argue that the
range of possibilities implied by the Standard would include (a) any of the
possible legal values, and (b) a rule for deducing the effect of the out of
range assignment. For example, if you have this: int x = INT_MAX + n (where
n is positive), then the implementation might say "it wraps around to
INT_MIN + n - 1", or something of that nature.

But an out-of-range assignment smells undefined from where I'm sitting.
 
J

jaysome

Keith Thompson said:


Well, yes, you're right - but because you're right, it is clear that the C99
Standard is broken (again). I'm thinking of alternative forms of main()
other than the two defined by the Standard. The Standard says that main()
may be defined "in some other implementation-defined manner" but, as far as
I can tell, no alternative possibilities are described. So the implementor
who wishes to provide an alternative main() interface has zero alternatives
from which to choose.

Where in the Standard does it say that alternative possibilities of
implementation-defined behavior must be described?

The way I read it, an implementation is conforming as long as it
documents something such as this:

void main(void)
{
return;
}
 
R

Richard Heathfield

jaysome said:
Where in the Standard does it say that alternative possibilities of
implementation-defined behavior must be described?

Like Keith, I was under the impression that the implementation does have to
choose from among possibilities provided by the Standard, but - remarkably
- I can find no evidence to support this impression at present. So either
Keith and I are both wrong about this, or I simply didn't look in the right
place just now. Either possibility is, of course, possible.
The way I read it, an implementation is conforming as long as it
documents something such as this:

void main(void)
{
return;
}

It's even conforming if it doesn't. No implementation is /required/ to
define the behaviour of void main programs.

But the code itself is not conforming, except when viewed as a
"MyFavouriteForgivingCompiler C" program rather than as a "C" program.
 
K

Keith Thompson

Richard Heathfield said:
jaysome said:

Like Keith, I was under the impression that the implementation does have to
choose from among possibilities provided by the Standard, but - remarkably
- I can find no evidence to support this impression at present. So either
Keith and I are both wrong about this, or I simply didn't look in the right
place just now. Either possibility is, of course, possible.

The definition changed between C90 and C99 (and again between C99 and
N1124).

C90 3.10:
implementation-defined behavior: Behavior. for a correct program
construct and correct data, that depends on the characteristics of
the implementation and that each implementation shall document.

C90 3.17:
unspecified behavior: Behavior, for a correct program construct
and correct data, for which this International Standard explicitly
imposes no requirements.

C99 3.4.1:
implementation-defined behavior

unspecified behavior where each implementation documents how the
choice is made

EXAMPLE An example of implementation-defined behavior is the
propagation of the high-order bit when a signed integer is
shifted right.

C99 3.4.4:
unspecified behavior

behavior where this International Standard provides two or more
possibilities and imposes no further requirements on which is
chosen in any instance

EXAMPLE An example of unspecified behavior is the order in which
the arguments to a function are evaluated.

(The definition of "unspecified behavior" was tweaked slightly in
N1124; the revised definition is "use of an unspecified value, or
other behavior where ...".)

C99 5.1.2.2.1 allows main() to be defined in either of the traditional
ways "or in some other implementation-defined manner". But this
doesn't use the term "implementation-defined behavior", which is
defined in section 3. The standard doesn't provide a definition of
"implementation-defined" other than in the context of
"implementation-defined behavior" or "implementation-defined value",
so I think we just have to read it as ordinary English text; "some
other implementation-defined manner" simply means "some other manner
which is defined (i.e., documented) by the implementation". For
implementation-defined *behavior*, the standard must provide two or
more possibilities; for implementation-defined anything-else, it
needn't do so.
It's even conforming if it doesn't. No implementation is /required/ to
define the behaviour of void main programs.

But the code itself is not conforming, except when viewed as a
"MyFavouriteForgivingCompiler C" program rather than as a "C" program.

Which is exactly what "conforming" means.

A *conforming program* is one that is acceptable to a conforming
implementation.

If I wrote a conforming implementation that allows
struct {char c; long double x;}main(void) {}
then that would become a conforming program. (The concept of a
"conforming program" isn't all that useful.)
 

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,995
Messages
2,570,228
Members
46,817
Latest member
AdalbertoT

Latest Threads

Top