Problem i C

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
svanted
Inlägg: 5276
Blev medlem: 30 augusti 2010, 21:20:38
Ort: Umeå

Problem i C

Inlägg av svanted »

blir f-n galen av detta?
en vanlig multiplikation?!?!?

Kod: Markera allt

#include <stdio.h>


void main( void )
{
unsigned long data2;


data2 = 0xf6 *  16777216;

printf("%lu\n", data2);

}

ger vid kompilering:
main3.c: In function 'main':
main3.c:9: warning: integer overflow in expression

men inte:

Kod: Markera allt

#include <stdio.h>


void main( void )
{
unsigned long data2;


data2 = 0xf6 *  11116777216;

printf("%lu\n", data2);

}
vad gör jag för fel?
Användarvisningsbild
Icecap
Inlägg: 26629
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: problem i c

Inlägg av Icecap »

Testa att casta:
data2 = (unsigned long)0xf6 * (unsigned long)16777216;

Eller:
data2 = 0xf6L * 16777216L;
Nerre
Inlägg: 27184
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: problem i c

Inlägg av Nerre »

Ja, är inte det där det klassiska problemet att om du multiplicerar två vanliga int så måste resultatet rymmas i en int, att det till vänster om likhetstecknet rymmer mer hjälper inte.

I det andra fallet så är det andra talet större än vad som ryms i en int, alltså castas hela högerledet till long (eller nåt sånt).

Att explicit casta till long är väl det rätta sättet, det ska väl formellt sett räcka med att den ena faktorn castas.
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: problem i c

Inlägg av sodjan »

I det första fallet får jag:

Kod: Markera allt

$ cc mult

data2 = 0xf6 *  16777216;
........^
%CC-W-INTOVERFL, In this statement, integer overflow occurs in evaluating the expression "0X00000000000000F6*16777216".
at line number 9 in file USER:[JANNE]MULT.C;1
$ 
I det andra fallet blir det:

Kod: Markera allt

$ cc mult2
data2 = 0xf6 *  11116777216;
........^
%CC-I-INTCONSTTRUNC, In this statement, conversion of the constant "0X00000000000000F6*11116777216" to unsigned long type will cause data loss.
at line number 9 in file USER:[JANNE]MULT2.C;1
$ 
Icecaps första förslag fungerar hos mig:

Kod: Markera allt

$ type mult3.c
#include <stdio.h>

void main( void )
{
  unsigned long data2;
  data2 = (unsigned long)0xf6 * (unsigned long)16777216;
  printf("%lu\n", data2);
}
$ 
$ cc mult3 
$ link mult3
$ run mult3
4127195136
$ 
Meddelanderna från kompilatorn har följande förklaringar:

Kod: Markera allt

$ help cc message INTOVERFL
CC
  Messages
    INTOVERFL

      Message        <Context> integer overflow occurs in evaluating the
                     expression "<expression>".

      Description    An integer overflow occurred while evaluating a
                     constant expression.  The value of the expression is
                     undefined.

      User Action    Correct the constant expression so that it does not
                     overflow.

Kod: Markera allt

$ help cc message INTCONSTTRUNC

CC
  Messages
    INTCONSTTRUNC

      Message        <Context> conversion of the constant "<constant>" to
                     <type> type will cause data loss.

      Description    A constant is converted to a type that is too small
                     to hold the constant value.  Data will be lost in the
                     conversion.

      User Action    If this is what you intended, cast the constant to
                     the desired type.  You might also want to mask off
                     the high-order bits before casting in order to avoid
                     optional message intconcasttru, which reports data
                     loss caused by casts.
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: problem i c

Inlägg av sodjan »

Nu så kan det vara värt att notera att det "bara" är varningar och både den första exemplet och
Icecap's version ger samma resultat wid körning:

Kod: Markera allt

$ cc mult

data2 = 0xf6 *  16777216;
........^
%CC-W-INTOVERFL, In this statement, integer overflow occurs in evaluating the expression "0X00000000000000F6*16777216".
at line number 9 in file USER:[JANNE]MULT.C;1
$
$ link mult
%LINK-W-WRNERS, compilation warnings in module MULT file USER:[JANNE]MULT.OBJ;11
$
$ run mult
4127195136
$
Det har väl med att göra att värderna var valda så att det ändå fungerar...
svanted
Inlägg: 5276
Blev medlem: 30 augusti 2010, 21:20:38
Ort: Umeå

Re: problem i c

Inlägg av svanted »

tack..
intressant var ju att det funkade utan cast med små och stora konstanter men inte med den jag ville använda, 16777216...
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: problem i c

Inlägg av sodjan »

För mig så blev det ju en "Warning" i första fallet och en "Information"
i det andra. Du verkade inte få något i andra fallet, men det
skiljer säkert mellan kompilatorer. Om jag drar på "känsligheten"
så klagar min kompilator på andra saker som inte har med
just multiplikationen att göra... :-)
svanted
Inlägg: 5276
Blev medlem: 30 augusti 2010, 21:20:38
Ort: Umeå

Re: problem i c

Inlägg av svanted »

för mig blev det helgalet då jag använde samma rad i ett program där hex konstaten var ett 8 bitars värde utläst från en fil...
det funkade om värdet i filen var litet typ < 0x30, för större tal räknade den kapitalt fel..
data2 = (unsigned char)fileData[30] * 16777216
värdet i filen är 0xf6
där blev data2 = 18446744073541779456 istf 4127195136
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: problem i c

Inlägg av sodjan »

Det ser ut som något problem med signed/unsigned eller liknande.
Jag får en varning för det där uttrycket:

Kod: Markera allt

data2 = (unsigned char) 0xf6 *  16777216;
........^
%CC-W-INTOVERFL, In this statement, integer overflow occurs in evaluating the expression "(unsigned char)0X00000000000000F6*16777216".
at line number 7 in file USER:[JANNE]MULT4.C;2
Om jag lägger till "(unsigned int) 16777216" så försvinner varningen.
Det ger dock "rätt" svar i båda fallen...

Om jag slår på lite mer meddelanden så får jag:

Kod: Markera allt

$ cc mult4.c/list/mach/noopt/warn=(enab=level6,verbose)

void main( void )
^
%CC-I-MAINNOTINT, Strict standard C extension: The declaration of the "main" function has a return type other than int.
at line number 3 in file USER:[JANNE]MULT4.C;11
Description: Standard C requires that the "main" function be defined with a return type of int.  HP C will accept other
return types, but the program does not conform to the C standard.  The status value returned to the environment
may not be what you expect, and other C compilers may not accept the definition as written. 
User Action: Define the "main" function with a return type of int for maximal portability. 

data2 = in1 * 16777216;
........^
%CC-I-VALUEPRES, In this statement, the conversion of the unsigned char/short value "in1" to signed int shows one
example of this program's use of value-preserving integral promotion.  This differs from the unsigned-preserving
semantics of some older C compilers.
at line number 11 in file USER:[JANNE]MULT4.C;11
Description: This expression shows one of possibly many places where this compilation uses value-preserving
semantics for small integer promotions rather than unsigned-preserving semantics used by some older compilers.
In cases where an unsigned char or unsigned short int is promoted to an integer, there are two different ways
the convert could happen.  Standard C requires that the type be converted to a signed int (value-preserving
semantics) while some older compilers will convert to an unsigned int (unsigned-preserving semantics). The
difference in the choice of int or unsigned int can have an impact on results of expressions that use the converted
value. The compiler cannot determine whether or not a particular instance of this usage will cause an observable
behavior difference in the program.  For more information, consult Section 3.2.1.1 of the "Rationale for ANSI C". 
User Action: Be aware that older, non-standard compilers might interpret this expression differently. 

printf("%lu\n", data2);
^
%CC-I-IGNORECALLVAL, In this statement, the value returned from the function "printf(...)" is not used - if this
is intended, it should be cast to "void".
at line number 12 in file USER:[JANNE]MULT4.C;11
Description: A function that returns a value has been invoked, yet the value was not used. This might not have
been what you intended. 
User Action: Cast the function to void to suppress the message. 
$
Inklusive ett lästips... :-)
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: Problem i C

Inlägg av blueint »

Lägg in "printf("%d\n", (int)sizeof(data2) );". Svaret borde ge en hint till problemlösningen.
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Problem i C

Inlägg av sodjan »

Jag får:

$ run mult4
4
4127195136

En annan sak...

Jag får varningen vid värden på konstaten som är 0x80 eller högre
För 0x7F eller lägre försvinner varningen. Har sannolikt med signed
att göra (d.v.s om högsta biten är satt eller inte). Explicit cast
till unsigned löser ju det...
Användarvisningsbild
Icecap
Inlägg: 26629
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Problem i C

Inlägg av Icecap »

Det beror oftast på att kompilern är ställd till att alla icke-castade konstanter ska behandlas som signed. Det är ett val man ofta kan ställa i kompilern.

Samtidig anser jag att man aldrig ska ha icke-castade värden så det är ju en idé att casta alla värden alla gångar.
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Problem i C

Inlägg av sodjan »

Ja, det stämmer även med förslaget under "User Action" här:

Kod: Markera allt

data2 = 0xf6 * 16777216;
........^
%CC-I-INTCONSTSIGN, In this statement, conversion of the constant "0X00000000000000F6*16777216" to
unsigned long type will cause a change in sign.
at line number 10 in file USER:[JANNE]MULT4.C;17

Description: Either an unsigned type was assigned a negative constant value, or a signed type was
assigned a positive contant value which will be evalated as a negative number after the assignment. 
Note that this message is not output for assignments to 1-bit bit fields. The message bitconstsign
is generated in that case. 

User Action: If this is what you intended, cast the constant to the desired type. You might also want
to change the constant to the correct signed or unsigned value in order to avoid the optional message
intconcastsgn, which reports sign changes caused by casts.
Varningen försvinner även med "data2 = 0xf6U * 16777216;"
Ett "U" efter värdet kanske är samma som som "(unsigned char)" före...
hummel
Inlägg: 2535
Blev medlem: 28 november 2009, 10:40:52
Ort: Stockholm

Re: Problem i C

Inlägg av hummel »

Helt klart blandas signed och unsigned
Ange alltid med U på konstanter för att förtydliga att det gäller unsigned. Sedan kan man fråga sig varför 0xFF är signed i C…

För att göra koden mer lättläst och underhållbar använd aldrig magic numbers i koden.
Findecanor
Inlägg: 1044
Blev medlem: 2 juli 2010, 23:04:07

Re: Problem i C

Inlägg av Findecanor »

Enklast att göra om till:

Kod: Markera allt

data2 = 0xf6UL *  16777216UL;
Det är U'na som gör det.
Skriv svar