Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Help me understand this compiler warning.

Reply
Thread Tools

Help me understand this compiler warning.

 
 
Charles Sullivan
Guest
Posts: n/a
 
      08-12-2006
I have a program written in C under Linux (gcc) which a user has
ported to run under AT&T SysV R4.

He sent me a copy of his makelog which displays a large number
of compiler warnings similar to this:

warning: semantics of ">>" change in ANSI C; use explicit cast

The statement to which this applies is:
xuc = ((uc[7] & 0xF0 ) >> 4);

where the declarations for xuc and uc are:
extern unsigned char xuc;
unsigned char uc[20];

I assume this warning means his compiler expects the number
4 in that statement to be cast as an unsigned char, but I
haven't yet found a warning level switch in my gcc compiler
which displays this warning, so can't be sure. There's no
such warning for another statement in the same function:
xi = uc[8] + (uc[9] << ;

where in this case:
extern int xi;

Is his compiler being overly picky or is the (apparently
expected) cast something that should be done in well-written
C code?

(Note: the variable names shown are simplified for clarity;
the actual names used are much more self-explanatory).

Thanks for your help.

Regards,
Charles Sullivan





 
Reply With Quote
 
 
 
 
Morris Dovey
Guest
Posts: n/a
 
      08-12-2006
Charles Sullivan (in http://www.velocityreviews.com/forums/(E-Mail Removed))
said:

| I have a program written in C under Linux (gcc) which a user has
| ported to run under AT&T SysV R4.
|
| He sent me a copy of his makelog which displays a large number
| of compiler warnings similar to this:
|
| warning: semantics of ">>" change in ANSI C; use explicit cast
|
| The statement to which this applies is:
| xuc = ((uc[7] & 0xF0 ) >> 4);
|
| where the declarations for xuc and uc are:
| extern unsigned char xuc;
| unsigned char uc[20];

Try:

xuc = ((uc[7] & 0xF0u) >> 4);

I'd use:

xuc = (uc[7] >> 4) & 0x0F;

to ensure that the shifted portion is not promoted to an int.

--
Morris Dovey
DeSoto Solar
DeSoto, Iowa USA
http://www.iedu.com/DeSoto


 
Reply With Quote
 
 
 
 
pete
Guest
Posts: n/a
 
      08-12-2006
Morris Dovey wrote:
>
> Charles Sullivan (in (E-Mail Removed))
> said:
>
> | I have a program written in C under Linux (gcc) which a user has
> | ported to run under AT&T SysV R4.
> |
> | He sent me a copy of his makelog which displays a large number
> | of compiler warnings similar to this:
> |
> | warning: semantics of ">>" change in ANSI C; use explicit cast
> |
> | The statement to which this applies is:
> | xuc = ((uc[7] & 0xF0 ) >> 4);


I think the compiler wants to see it this way:

xuc = (unsigned char)((uc[7] & 0xF0 ) >> 4);

> |
> | where the declarations for xuc and uc are:
> | extern unsigned char xuc;
> | unsigned char uc[20];
>
> Try:
>
> xuc = ((uc[7] & 0xF0u) >> 4);
>
> I'd use:
>
> xuc = (uc[7] >> 4) & 0x0F;
>
> to ensure that the shifted portion is not promoted to an int.


I don't think that does what you want.

N869
6.5.7 Bitwise shift operators

[#3] The integer promotions are performed on each of the
operands.

--
pete
 
Reply With Quote
 
ena8t8si@yahoo.com
Guest
Posts: n/a
 
      08-12-2006

Charles Sullivan wrote:
> I have a program written in C under Linux (gcc) which a user has
> ported to run under AT&T SysV R4.
>
> He sent me a copy of his makelog which displays a large number
> of compiler warnings similar to this:
>
> warning: semantics of ">>" change in ANSI C; use explicit cast
>
> The statement to which this applies is:
> xuc = ((uc[7] & 0xF0 ) >> 4);
>
> where the declarations for xuc and uc are:
> extern unsigned char xuc;
> unsigned char uc[20];
>
> I assume this warning means his compiler expects the number
> 4 in that statement to be cast as an unsigned char, but I
> haven't yet found a warning level switch in my gcc compiler
> which displays this warning, so can't be sure. There's no
> such warning for another statement in the same function:
> xi = uc[8] + (uc[9] << ;
>
> where in this case:
> extern int xi;
>
> Is his compiler being overly picky or is the (apparently
> expected) cast something that should be done in well-written
> C code?


This question is a very good question but not
an easy one to answer.

The warning is intended to alert a programmer to
a potential problem but which isn't a problem
in this case. The code as written will work
fine.

I myself wouldn't want to write a cast here. I
would if I had to to shut the compiler up, but
before that I would try

xuc = (uc[7] & 0xF0u) >> 4;

or

xuc = (uc[7] >> 4) & 0xF;

(probably in that order) and see if one of those
helped. If one did, I'd use that in preference
to casting.

 
Reply With Quote
 
Morris Dovey
Guest
Posts: n/a
 
      08-13-2006
pete (in (E-Mail Removed)) said:

| Morris Dovey wrote:
||
|| Charles Sullivan (in (E-Mail Removed))
|| said:
||
||| I have a program written in C under Linux (gcc) which a user has
||| ported to run under AT&T SysV R4.
|||
||| He sent me a copy of his makelog which displays a large number
||| of compiler warnings similar to this:
|||
||| warning: semantics of ">>" change in ANSI C; use explicit cast
|||
||| The statement to which this applies is:
||| xuc = ((uc[7] & 0xF0 ) >> 4);
|
| I think the compiler wants to see it this way:
|
| xuc = (unsigned char)((uc[7] & 0xF0 ) >> 4);

Since xuc is unsigned. Casting the result isn't necessary in order for
the assignment to be made as intended. ANDing an unsigned char with an
int /could/ produce a signed int - which, according to 6.5.7(5), could
produce an implementation-defined shifted result.

Better to ensure that the quantity to be shifted is unsigned.

||| where the declarations for xuc and uc are:
||| extern unsigned char xuc;
||| unsigned char uc[20];
||
|| Try:
||
|| xuc = ((uc[7] & 0xF0u) >> 4);
||
|| I'd use:
||
|| xuc = (uc[7] >> 4) & 0x0F;
||
|| to ensure that the shifted portion is not promoted to an int.
|
| I don't think that does what you want.
|
| N869
| 6.5.7 Bitwise shift operators
|
| [#3] The integer promotions are performed on each of the
| operands.

You appear to have missed that part of 6.7.5(3) that says the result
will have the type of the promoted left operand - unsigned if done as
I suggest.

6.3.1.8(1) - rules for integer promotions - adds a bit of
clarification (sort of).

--
Morris Dovey
DeSoto Solar
DeSoto, Iowa USA
http://www.iedu.com/DeSoto


 
Reply With Quote
 
Jack Klein
Guest
Posts: n/a
 
      08-13-2006
On Sat, 12 Aug 2006 21:25:56 GMT, Charles Sullivan
<(E-Mail Removed)> wrote in comp.lang.c:

> I have a program written in C under Linux (gcc) which a user has
> ported to run under AT&T SysV R4.
>
> He sent me a copy of his makelog which displays a large number
> of compiler warnings similar to this:
>
> warning: semantics of ">>" change in ANSI C; use explicit cast


Prior to the adoption of the 1989/1990 ANSI/ISO standard, some
compilers applied different rules for promoting unsigned types.

> The statement to which this applies is:
> xuc = ((uc[7] & 0xF0 ) >> 4);
>
> where the declarations for xuc and uc are:
> extern unsigned char xuc;
> unsigned char uc[20];


Assuming 8-bit characters, which is true of every Linux I have ever
heard of, then uc[7] has a value between 0 and 255 inclusive. Under
any ANSI/ISO version of C, this will cause uc[7] to be promoted to
signed int, since a signed int can hold all the values of an unsigned
char. This is called a "value preserving" promotion.

On the other hand, some pre-standard compilers performed what might be
called "unsigned preserving" promotions. Unsigned char promoted to
unsigned int and unsigned int promoted to unsigned long.

If the pre-standard C compiler for the AT&T implementation used the
old rules, the uc[7] would promote to an unsigned int with a value
between 0 and 255. This would cause a conversion of integer literal
0xF0 to unsigned int, and the bitwise and would be performed on the
two unsigned ints, producing an unsigned int result, which was finally
shifted right.

Under the new rules, uc[7] is promoted to a signed int with a value
between 0 and 255. Since the integer literal 0xF0 already has type
signed int, it is not converted and the bitwise and takes place on two
signed int values, generating a signed int result. This signed int
result is then shifted right.

There are potential surprises in right shifting signed ints (or signed
longs, for that matter) with negative values. It is
implementation-defined whether the sign bit is maintained or
discarded.

In this particular case, however, you will be right shifting a signed
int with a positive value, and this is absolutely well defined as long
as the shift count is within range, which is certainly is. Signed
integer types with a positive value are defined by the standard to
have identical bit representations as the corresponding unsigned types
with the same value, and right shifting yields the same result.

So due to the values used in this case, there is no actual possibility
of a different result on any implementation. With other values,
specifically those that involve right shifting a signed integer type
with a negative value, there could be a difference in the result. The
compiler is warning about the possibility in the abstract, not
checking to see whether it could happen with the specific values in
this particular case.

> I assume this warning means his compiler expects the number
> 4 in that statement to be cast as an unsigned char, but I


That's a totally incorrect assumption. The type of the right operand,
the shift count, does not play any value at all in any promotion of
the left operand or the type of the result. If the type of the shift
count is less than int, it is promoted to either signed or unsigned
int, but the type on which the operation is performed, and the type of
the result, is based strictly on the promoted type of the left
operand.

> haven't yet found a warning level switch in my gcc compiler
> which displays this warning, so can't be sure. There's no
> such warning for another statement in the same function:
> xi = uc[8] + (uc[9] << ;
>
> where in this case:
> extern int xi;
>
> Is his compiler being overly picky or is the (apparently
> expected) cast something that should be done in well-written
> C code?
>
> (Note: the variable names shown are simplified for clarity;
> the actual names used are much more self-explanatory).
>
> Thanks for your help.


The code is actually correct, well-defined, and fully portable. But
if you want to eliminate the warning, as Morris suggested, change the
type of the integer literal:

xuc = ((uc[7] & 0xF0u) >> 4);

This should eliminate it.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
 
Reply With Quote
 
pete
Guest
Posts: n/a
 
      08-13-2006
Morris Dovey wrote:
>
> pete (in (E-Mail Removed)) said:
>
> | Morris Dovey wrote:
> ||
> || Charles Sullivan (in (E-Mail Removed))
> || said:
> ||
> ||| I have a program written in C under Linux (gcc) which a user has
> ||| ported to run under AT&T SysV R4.
> |||
> ||| He sent me a copy of his makelog which displays a large number
> ||| of compiler warnings similar to this:
> |||
> ||| warning: semantics of ">>" change in ANSI C; use explicit cast
> |||
> ||| The statement to which this applies is:
> ||| xuc = ((uc[7] & 0xF0 ) >> 4);
> |
> | I think the compiler wants to see it this way:
> |
> | xuc = (unsigned char)((uc[7] & 0xF0 ) >> 4);
>
> Since xuc is unsigned. Casting the result isn't necessary in order for
> the assignment to be made as intended. ANDing an unsigned char with an
> int /could/ produce a signed int - which, according to 6.5.7(5), could
> produce an implementation-defined shifted result.
>
> Better to ensure that the quantity to be shifted is unsigned.
>
> ||| where the declarations for xuc and uc are:
> ||| extern unsigned char xuc;
> ||| unsigned char uc[20];
> ||
> || Try:
> ||
> || xuc = ((uc[7] & 0xF0u) >> 4);
> ||
> || I'd use:
> ||
> || xuc = (uc[7] >> 4) & 0x0F;
> ||
> || to ensure that the shifted portion is not promoted to an int.
> |
> | I don't think that does what you want.
> |
> | N869
> | 6.5.7 Bitwise shift operators
> |
> | [#3] The integer promotions are performed on each of the
> | operands.
>
> You appear to have missed that part of 6.7.5(3) that says the result
> will have the type of the promoted left operand - unsigned if done as
> I suggest.
>
> 6.3.1.8(1) - rules for integer promotions - adds a bit of
> clarification (sort of).


The left operand is uc[7], which is of type unsigned char.

Your posted code doesn't do anything to prevent
type unsigned char from being promoted to type int.

Why do you think that in
(uc[7] >> 4)
that the left operand won't be promoted to int?

"If an int can represent all values of the original type, the
value is converted to an int; otherwise, it is converted to
an unsigned int. These are called the integer
promotions."

--
pete
 
Reply With Quote
 
Morris Dovey
Guest
Posts: n/a
 
      08-13-2006
pete (in (E-Mail Removed)) said:

| The left operand is uc[7], which is of type unsigned char.
|
| Your posted code doesn't do anything to prevent
| type unsigned char from being promoted to type int.
|
| Why do you think that in
| (uc[7] >> 4)
| that the left operand won't be promoted to int?
|
| "If an int can represent all values of the original type, the
| value is converted to an int; otherwise, it is converted to
| an unsigned int. These are called the integer
| promotions."

You're absolutely right. I'm not sure how I managed it; but I looked
it up, read it carefully, and concluded that the unsigned char would
be promoted to an unsigned int - very wrong.

Thanks for getting me on track - and to the OP, my apologies for an
incorrect response.

--
Morris Dovey
DeSoto Solar
DeSoto, Iowa USA
http://www.iedu.com/DeSoto


 
Reply With Quote
 
Charles Sullivan
Guest
Posts: n/a
 
      08-16-2006
Many thanks to all who responded - Morris Dovey, pete, ena8t8si,
and Jack Klein. I especially appreciate Jack's detailed explanation
of the historical background.

Regards,
Charles Sullivan

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Read all of this to understand how it works. then check around on otherRead all of this to understand how it works. then check around on other thelisa martin Computer Support 2 08-18-2005 06:40 AM
Help with Constant Define--Compiler Issue with ANSI or my compiler or me? No Spam C Programming 7 01-04-2005 01:37 AM
can't understand the compiler messages forgotten field C++ 5 04-06-2004 02:59 PM
compiler error I don't understand Tobias Langner C++ 7 08-01-2003 09:44 PM
Compiler Error Message: The compiler failed with error code 128. Yan ASP .Net 0 07-21-2003 10:49 PM



Advertisments