|
|
|
|
||||||
![]() |
|
|
LinkBack | Outils de la discussion |
|
|
#1 |
|
Messages: n/a
Hébergeur: |
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 |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
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.) |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
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.) |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
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 |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
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" |
|
|
|
#6 |
|
Messages: n/a
Hébergeur: |
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" |
|
|
|
#7 |
|
Messages: n/a
Hébergeur: |
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>. |
|
|
|
#8 |
|
Messages: n/a
Hébergeur: |
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" |
|
|
|
#9 |
|
Messages: n/a
Hébergeur: |
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). |
|
![]() |
| Outils de la discussion | |
|
|