PHWinfo banniere

Titres
PORTAIL ANNUAIRE ARTICLES COMPARATEUR HÉBERGEURS DEVIS FORUMS RÉDUCTEUR D'URL
Précédent   PHWinfo > Autres forums > Forum Programmation & Conception > comp.lang.c > Integer multiplication truncation
S'inscrire FAQ Membres Recherche Messages du jour Marquer les forums comme lus
Integer multiplication truncation

Réponse
 
LinkBack Outils de la discussion
Vieux 02/02/2008, 12h46   #1
Mamluk Caliph
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Integer multiplication truncation

The following code executes as I would expect on gcc:

#include <inttypes.h>
#include <stdio.h>

int main(int argc, char **argv){
uint16_t apa = 10000;
uint16_t kaka = 7000;
uint32_t mazarin;

mazarin = apa*kaka;
printf("%lu \n",mazarin);
return 0;
}

I.e. it will print out the value 70000000. However, when I compile
this another compiler the result is truncated and I have to modify the
code to the following to make it run:

#include <inttypes.h>
#include <stdio.h>

int main(int argc, char **argv){
uint16_t apa = 10000;
uint16_t kaka = 7000;
uint32_t mazarin;

mazarin = (uint32_t)apa*kaka;
printf("%lu \n",mazarin);
return 0;
}


Could anybody explain this? Is this due to C99 improvements regarding
integer overflow? Is there any predefined macro one could use to
determine this special case?

(Note: The extended types in inttypes.h were added for the second
compiler.)


Regards
/Michael
  Réponse avec citation
Vieux 02/02/2008, 13h02   #2
Harald van Dijk
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Integer multiplication truncation

On Sat, 02 Feb 2008 04:46:32 -0800, Mamluk Caliph wrote:
> The following code executes as I would expect on gcc:
>
> #include <inttypes.h>
> #include <stdio.h>
>
> int main(int argc, char **argv){
> uint16_t apa = 10000;
> uint16_t kaka = 7000;
> uint32_t mazarin;
>
> mazarin = apa*kaka;
> printf("%lu \n",mazarin);


%lu is used to print a value of type unsigned long. What is the type of
mazarin?

> return 0;
> }
>
> I.e. it will print out the value 70000000. However, when I compile this
> another compiler the result is truncated and I have to modify the code
> to the following to make it run:
>
> mazarin = (uint32_t)apa*kaka;
>
> Could anybody explain this?


If uint16_t is a typedef for unsigned int (meaning unsigned int has 16
bits), multiplying one uint16_t by another uint16_t produces a value of
type uint16_t. It doesn't matter that you're going to store it in an
uint32_t. You need to force the multiplication to be done in a way that
it produces a result of type uint32_t (or wider), which is what the cast
does.

It happens to work on your GCC setup, because on that system (I'm going
to make assumptions), int happens to have 32 bits, and multiplying an
uint16_t (unsigned short) by another uint16_t produces a result of type
int, or unsigned int, depending on the system. Since your int has enough
bits to store the result, you get to actually see the result.

> Is this due to C99 improvements regarding
> integer overflow? Is there any predefined macro one could use to
> determine this special case?


There is nothing special happening here, and either result (or others) is
possible in both C90 and C99.

> (Note: The extended types in inttypes.h were added for the second
> compiler.)

  Réponse avec citation
Vieux 02/02/2008, 14h57   #3
Mamluk Caliph
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Integer multiplication truncation

I think I'm starting to understand and I can verify that an int type
on my GNU system is indeed 32 bits. I added the following line:

printf("%d %d %d %d
\n",sizeof(apa),sizeof(kaka),sizeof(mazarin),sizeo f(int));

which will output: 2 2 4 4

So if I understand this correctly, the result of an integer
multiplication is always an int no matter of the type of the operands?
Or does it mean that both operands are always up-casted to an int
before the operation?

What would happen if one of the operands would be 64 bits and the
values such that the result exceeds MAX_INT?

On Feb 2, 2:02 pm, Harald van D©¦k <true...@gmail.com> wrote:
> On Sat, 02 Feb 2008 04:46:32 -0800, Mamluk Caliph wrote:
> > The following code executes as I would expect on gcc:

>
> > #include <inttypes.h>
> > #include <stdio.h>

>
> > int main(int argc, char **argv){
> > uint16_t apa = 10000;
> > uint16_t kaka = 7000;
> > uint32_t mazarin;

>
> > mazarin = apa*kaka;
> > printf("%lu \n",mazarin);

>
> %lu is used to print a value of type unsigned long. What is the type of
> mazarin?


I see your point. I assumed that unsigned long would be larger than an
int, i.e. 32 bit's. On my GNU system a long actually is 32 bits - but
so on the other hand is int.

I added yet the following line:
printf("%d %d %d %d
\n",sizeof(char),sizeof(int),sizeof(long),sizeof(l ong long));
which prints out: 1 4 4 8

I.e. mazarin (uint32_t) could be either unsigned int or unsigned long.
I don't know if it matters which since both seems to be of the same
size on my system.

By the way, I tried defining my own types and thought I could do
something as follows:

#if sizeof(int)==4
typedef int myInt32_t;
#endif

This results in a compilation error `missing binary operator before
token "("`, why is that? I thought sizof was just a macro.

>
> > return 0;
> > }

>
> > I.e. it will print out the value 70000000. However, when I compile this
> > another compiler the result is truncated and I have to modify the code
> > to the following to make it run:

>
> > mazarin = (uint32_t)apa*kaka;

>
> > Could anybody explain this?

>
> If uint16_t is a typedef for unsigned int (meaning unsigned int has 16
> bits), multiplying one uint16_t by another uint16_t produces a value of
> type uint16_t. It doesn't matter that you're going to store it in an
> uint32_t. You need to force the multiplication to be done in a way that
> it produces a result of type uint32_t (or wider), which is what the cast
> does.
>
> It happens to work on your GCC setup, because on that system (I'm going
> to make assumptions), int happens to have 32 bits, and multiplying an
> uint16_t (unsigned short) by another uint16_t produces a result of type
> int, or unsigned int, depending on the system. Since your int has enough
> bits to store the result, you get to actually see the result.
>
> > Is this due to C99 improvements regarding
> > integer overflow? Is there any predefined macro one could use to
> > determine this special case?

>
> There is nothing special happening here, and either result (or others) is
> possible in both C90 and C99.
>
> > (Note: The extended types in inttypes.h were added for the second
> > compiler.)

  Réponse avec citation
Vieux 02/02/2008, 17h26   #4
Thad Smith
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Integer multiplication truncation

Mamluk Caliph wrote:
> I think I'm starting to understand and I can verify that an int type
> on my GNU system is indeed 32 bits. I added the following line:
>
> printf("%d %d %d %d
> \n",sizeof(apa),sizeof(kaka),sizeof(mazarin),sizeo f(int));
>
> which will output: 2 2 4 4
>
> So if I understand this correctly, the result of an integer
> multiplication is always an int no matter of the type of the operands?
> Or does it mean that both operands are always up-casted to an int
> before the operation?


The type of the product is the type of the promoted operands. First, the
individual operands undergo default integer promotion, which would make
each at least the size of an int. If either operand has greater rank than
int, the other operand is promoted to that type and the result is also that
type.

> What would happen if one of the operands would be 64 bits and the
> values such that the result exceeds MAX_INT?


If the product of integer types is greater than can be expressed in the
resulting type, the value of the result depends on whether the resulting
type is signed or unsigned. If unsigned, the lower bits of the product are
kept. If the resulting type is signed, the result is undefined by the C
Standard.

--
Thad
  Réponse avec citation
Vieux 02/02/2008, 20h58   #5
Keith Thompson
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Integer multiplication truncation

Mamluk Caliph <mamluk.caliph@gmail.com> writes:
> The following code executes as I would expect on gcc:
>
> #include <inttypes.h>
> #include <stdio.h>
>
> int main(int argc, char **argv){
> uint16_t apa = 10000;
> uint16_t kaka = 7000;
> uint32_t mazarin;
>
> mazarin = apa*kaka;
> printf("%lu \n",mazarin);
> return 0;
> }
>
> I.e. it will print out the value 70000000. However, when I compile
> this another compiler the result is truncated and I have to modify the
> code to the following to make it run:

[snip]

The types uint16_t and uint32_t are declared in <stdint.h>, not in
<inttypes.h>. It happens that <inttypes.h> includes <stdint.h>, which
is why your program compiles, but the purpose of <inttypes.h> is to
define format conversions for use with the *printf and *scanf
functions.

If you just want the types, you should include <stdint.h> rather than
<inttypes.h>.

But the macros in <inttypes.h> are one possible solution to your
problem. The trouble, IMHO, is that they're ugly. For example, your
printf call would be:

printf("%" PRIu32 "\n", mazarin);

Another solution is to convert the value to a type for which you know
the format. Since unsigned long is guaranteed to be a least 32 bits,
you can safely use "%lu" *if* you explicitly convert the value:

printf("%lu\n", (unsigned long)mazarin);

For wider types you might need to use "%zd" or "%zu" with intmax_t or
uintmax_t, defined in <stdint.h> -- but only if your printf
implementation supports them (not all do).

--
Keith Thompson (The_Other_Keith) <kst-u@mib.org>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
  Réponse avec citation
Vieux 02/02/2008, 21h17   #6
Keith Thompson
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Integer multiplication truncation

Mamluk Caliph <mamluk.caliph@gmail.com> writes:
[...]
> By the way, I tried defining my own types and thought I could do
> something as follows:
>
> #if sizeof(int)==4
> typedef int myInt32_t;
> #endif
>
> This results in a compilation error `missing binary operator before
> token "("`, why is that? I thought sizof was just a macro.

[...]

No, sizeof is a built-in unary operator. (Its symbol happens to be a
keyword rather than a punctuation symbol.) The preprocessor doesn't
the "sizeof" or "int" keywords, so you can't use "sizeof(int)" in a
"#if" directive.

You can use the macros defined in <limits.h> in preprocessor
directives, though, and since these specify the ranges that the types
can represent rather than the sizes of their representations, they
might be more appropriate.

--
Keith Thompson (The_Other_Keith) <kst-u@mib.org>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
  Réponse avec citation
Vieux 02/02/2008, 21h35   #7
Harald van Dijk
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Integer multiplication truncation

On Sat, 02 Feb 2008 12:58:31 -0800, Keith Thompson wrote:
> The types uint16_t and uint32_t are declared in <stdint.h>, not in
> <inttypes.h>. It happens that <inttypes.h> includes <stdint.h>, which
> is why your program compiles, but the purpose of <inttypes.h> is to
> define format conversions for use with the *printf and *scanf functions.


No, the purpose of <inttypes.h> is to define format specifiers for the
*printf and *scanf functions, as well as to provide the typedefs that
these format specifiers are meant to be used with. <inttypes.h> is the
historical header that C99 adopted and extended.

> If you just want the types, you should include <stdint.h> rather than
> <inttypes.h>.


<stdint.h> is a new invention in C99 intended to provide a subset of the
features of <inttypes.h> that can be required by freestanding
implementations (possibly lacking standard I/O). It incidentally happens
to have a possible benefit even for hosted implementations, but that
doesn't mean there's anything wrong with using <inttypes.h>.
  Réponse avec citation
Vieux 02/02/2008, 21h55   #8
Keith Thompson
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Integer multiplication truncation

Harald van Dijk <truedfx@gmail.com> writes:
> On Sat, 02 Feb 2008 12:58:31 -0800, Keith Thompson wrote:
>> The types uint16_t and uint32_t are declared in <stdint.h>, not in
>> <inttypes.h>. It happens that <inttypes.h> includes <stdint.h>, which
>> is why your program compiles, but the purpose of <inttypes.h> is to
>> define format conversions for use with the *printf and *scanf functions.

>
> No, the purpose of <inttypes.h> is to define format specifiers for the
> *printf and *scanf functions, as well as to provide the typedefs that
> these format specifiers are meant to be used with. <inttypes.h> is the
> historical header that C99 adopted and extended.
>
>> If you just want the types, you should include <stdint.h> rather than
>> <inttypes.h>.

>
> <stdint.h> is a new invention in C99 intended to provide a subset of the
> features of <inttypes.h> that can be required by freestanding
> implementations (possibly lacking standard I/O). It incidentally happens
> to have a possible benefit even for hosted implementations, but that
> doesn't mean there's anything wrong with using <inttypes.h>.


Interesting, I didn't know the historical context. I had assumed that
both <inttypes.h> and <stdint.h> were invented for C99 (certainly
neither existed in C89, C90, or C95). I suppose that explains the
seemingly counterintuitive name for <inttypes.h>. I had never paid
much attention to that header before; I just noticed that, in addition
to the macros for format specifiers, it also defines several functions
that operate on intmax_t and uintmax_t, corresponding to some
previously existing functions for the [un]signed [long] int types.

But regardless of the origins of the two headers, they were introduced
to standard C simultaneously, and <inttypes.h>'s history as a
non-standard header doesn't influence my decision whether to use it or
not. If I'm just going to use the typedefs declared in <stdint.h>,
I'd still rather just use <stdint.h> and avoid bringing in all the
other stuff. The formatting macros are nice, I suppose, but I
personally find them unwieldy, and for most purposes I'd rather just
convert to some type for which there's a built-in format string.
YMMV, of course.

--
Keith Thompson (The_Other_Keith) <kst-u@mib.org>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
  Réponse avec citation
Vieux 03/02/2008, 12h02   #9
Mamluk Caliph
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Integer multiplication truncation

On Feb 2, 10:55 pm, Keith Thompson <ks...@mib.org> wrote:
> Harald van D©¦k <true...@gmail.com> writes:
>
>
>
> > On Sat, 02 Feb 2008 12:58:31 -0800, Keith Thompson wrote:
> >> The types uint16_t and uint32_t are declared in <stdint.h>, not in
> >> <inttypes.h>. It happens that <inttypes.h> includes <stdint.h>, which
> >> is why your program compiles, but the purpose of <inttypes.h> is to
> >> define format conversions for use with the *printf and *scanf functions..

>
> > No, the purpose of <inttypes.h> is to define format specifiers for the
> > *printf and *scanf functions, as well as to provide the typedefs that
> > these format specifiers are meant to be used with. <inttypes.h> is the
> > historical header that C99 adopted and extended.

>
> >> If you just want the types, you should include <stdint.h> rather than
> >> <inttypes.h>.

>
> > <stdint.h> is a new invention in C99 intended to provide a subset of the
> > features of <inttypes.h> that can be required by freestanding
> > implementations (possibly lacking standard I/O). It incidentally happens
> > to have a possible benefit even for hosted implementations, but that
> > doesn't mean there's anything wrong with using <inttypes.h>.

>
> Interesting, I didn't know the historical context. I had assumed that
> both <inttypes.h> and <stdint.h> were invented for C99 (certainly
> neither existed in C89, C90, or C95). I suppose that explains the
> seemingly counterintuitive name for <inttypes.h>. I had never paid
> much attention to that header before; I just noticed that, in addition
> to the macros for format specifiers, it also defines several functions
> that operate on intmax_t and uintmax_t, corresponding to some
> previously existing functions for the [un]signed [long] int types.
>
> But regardless of the origins of the two headers, they were introduced
> to standard C simultaneously, and <inttypes.h>'s history as a
> non-standard header doesn't influence my decision whether to use it or
> not. If I'm just going to use the typedefs declared in <stdint.h>,
> I'd still rather just use <stdint.h> and avoid bringing in all the
> other stuff. The formatting macros are nice, I suppose, but I
> personally find them unwieldy, and for most purposes I'd rather just
> convert to some type for which there's a built-in format string.
> YMMV, of course.
>
> --
> Keith Thompson (The_Other_Keith) <ks...@mib.org>
> Nokia
> "We must do something. This is something. Therefore, we must do this."
> -- Antony Jay and Jonathan Lynn, "Yes Minister"


Thanks Keith, Harald and Thad. Your inputs have been most ful in
ing me understanding this problem (and also possibly avoid a few
future bugs).

  Réponse avec citation
Réponse


Outils de la discussion

Règles de messages
Vous ne pouvez pas créer de nouvelles discussions
Vous ne pouvez pas envoyer des réponses
Vous ne pouvez pas envoyer des pièces jointes
Vous ne pouvez pas modifier vos messages

Les balises BB sont activées : oui
Les smileys sont activés : oui
La balise [IMG] est activée : oui
Le code HTML peut être employé : non
Trackbacks are oui
Pingbacks are oui
Refbacks are oui


Fuseau horaire GMT +1. Il est actuellement 14h05.


Édité par : vBulletin® version 3.7.3
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.2.0 RC5 Tous droits réservés.
Version française #16 par l'association vBulletin francophone
PHWinfo est un site Éducation Sans Frontières ©2000-2008
Ad Management by RedTyger
©Tous droits réservés par les parties respectives
Page generated in 0,21166 seconds with 17 queries