C: Another type promotion question

cleverhandle

Diamond Member
Dec 17, 2001
3,566
3
81
Question: Suppose that i is a variable of type int, l is a variable of type long int, and u is a variable of type unsigned int. What is the type of the expression i + (int) l * u?

I figured that l gets cast to int first, then multiplied with u, which promotes l to unsigned int. Then the product (an unsigned int) is added to i, which promotes i to an unsigned int. So the expression as a whole is an unsigned int. I've got no answers and - as I'm on my own - no prof or TA, so I put together the following code and ran it through splint to check:

#include <stdio.h>

#define TESTTYPE unsigned int
#define TESTEXPR (i + (int) l * u)

int main()
{
TESTTYPE t = 0;

int i = 100;
long l = 1000;
unsigned int u = 3000000000;

if ( t == TESTEXPR )
printf("Yippee!\n");

return 0;
}

Splint, however, claims that TESTEXPR is an int, not an unsigned int. Assuming my method of checking is valid (?), why does the expression end up as an int?
 

manly

Lifer
Jan 25, 2000
13,356
4,113
136
It's misguided to think an unsigned is a "wider" type than the regular integer. On our systems for example, both are 32 bits, and store the same set of bit patterns.

The interpretation of those binary values just happens to be different.
 

cleverhandle

Diamond Member
Dec 17, 2001
3,566
3
81
OK, sorry - I was using "promotions" incorrectly. As you say (and I knew), the unsigned types are no wider than the signed types. I should be talking about the "usual arithmetic conversions". And according to those, summarized here, (int) l should be converted to unsigned int when multiplied by u, no?

edit: s/divided/multiplied/
 

Cat

Golden Member
Oct 10, 1999
1,059
0
0
How about

#define TESTEXPR (i + ((int) l) * u)

To make sure that you aren't casting l*u->int. Yes, I know that the operator precedence of (typecast) should cast l to an int, then multiply u, but perhaps splint is faulty there. I doubt it though. But just check first, and see what happens.

 

cleverhandle

Diamond Member
Dec 17, 2001
3,566
3
81
Even with the copious parentheses of:

( i + (((int) l) * u) )

splint still claims the expression is an int. So...?
 

Cat

Golden Member
Oct 10, 1999
1,059
0
0
What does splint declare (((int) l) * u) to be?

I should just get a lint program. :)
 

cleverhandle

Diamond Member
Dec 17, 2001
3,566
3
81
Splint claims (((int) l) * u) is an int, even when I pick values that would overflow a signed int but fit in an unsigned int.
 

Cat

Golden Member
Oct 10, 1999
1,059
0
0
So we know the offending result occurs from that expression.

Actually, what is (i + u) according to splint?
"" (l + u)
"" ((int) l)
 

cleverhandle

Diamond Member
Dec 17, 2001
3,566
3
81
Interesting...

Originally posted by: Cat
Actually, what is (i + u) according to splint?
Int. (Didn't expect that.)
"" (l + u)
Long. (Makes sense.)
"" ((int) l)
Int. (Also makes sense.)

So computing on an int and an unsigned int doesn't convert to an unsigned int as I had expected. But it appears that the int "should" be converted to unsigned according to the standards, no?

edit: bah, just noticed I had my to's and from's mixed up at the end... fixed now.
 

Cat

Golden Member
Oct 10, 1999
1,059
0
0
Ah, splint is from my alma mater. It can't be wrong ;) I know David Evans, so I can ask him personally if you want.
 

cleverhandle

Diamond Member
Dec 17, 2001
3,566
3
81
Originally posted by: Cat
http://www.cse.unsw.edu.au/~patrykz/TenDRA/tdfc/tdfc7.html#S33

This also seems to confirm ( int + unsigned int ) results in unsigned int.
Yeah, both that page and the one I pointed to seem to be basically quoting the ANSI standard. (Is that available online, BTW? Or is it a paid kind of thing?) And splint's man page says that it it uses the ANSI libs by default. Passing the "-ansi-lib" flag gives the same result also.
Ah, splint is from my alma mater. It can't be wrong I know David Evans, so I can ask him personally if you want.
If you don't mind doing that, I'd certainly like to hear his opinion. I'm not a "real" programmer, and may never become one, but I do like to be thorough with this sort of thing. Not understanding an implementation detail I'm OK with, but I'd like to understand at least the ideal. I'll see what the fellows on alt.comp.lang.learn.c-c++ have to say in the meantime.

Thanks for the help.

 

Ameesh

Lifer
Apr 3, 2001
23,686
1
0
on x86 with MSVC++ longs and ints are both 4 bytes

a int + long + uint should result in a uint

for instance
if you did:

int sumA, a = 0;
uint sumB, b = 0;
long c = 0;


sumA = a + b + c; // Should produce a compiler warning saying something like 32 bit quantity trying to go into 31 bit storage

sumB = a + b + c; // Should compile fine without any warnings
 

Cat

Golden Member
Oct 10, 1999
1,059
0
0
Yes, we know the correct behavior. What is puzzling is that splint is not agreeing with the spec, and splint is supposed to be all ABOUT the spec.
 

Ameesh

Lifer
Apr 3, 2001
23,686
1
0
Originally posted by: Cat
Yes, we know the correct behavior. What is puzzling is that splint is not agreeing with the spec, and splint is supposed to be all ABOUT the spec.

then simply put splint is wrong, it can happen you know, i have found bugs in many static code analyzers, not in splint but in lint.
 

Cat

Golden Member
Oct 10, 1999
1,059
0
0
We were dealing with gcc and Linux earlier. Yes, perhaps splint is wrong, but there may be something here that we haven't taken into account.

I don't mean to insult your programming experience, but with a statement talking about 31 bit storage, I don't completely trust you as the ISO C standards guru. :)
 

cleverhandle

Diamond Member
Dec 17, 2001
3,566
3
81
This is still linux - gcc-3.3/glibc-2.3. Sorry, should have mentioned it in the original post...
 

Ameesh

Lifer
Apr 3, 2001
23,686
1
0
Originally posted by: Cat
We were dealing with gcc and Linux earlier. Yes, perhaps splint is wrong, but there may be something here that we haven't taken into account.

I don't mean to insult your programming experience, but with a statement talking about 31 bit storage, I don't completely trust you as the ISO C standards guru. :)

well i did qualify my statement on x86 using the MS VC++ compiler.

and there is nothing to say that linux and gcc is 100% iso either.
 

Ameesh

Lifer
Apr 3, 2001
23,686
1
0
Originally posted by: cleverhandle
This is still linux - gcc-3.3/glibc-2.3. Sorry, should have mentioned it in the original post...

running on what platform? x86 i assume?
 

cleverhandle

Diamond Member
Dec 17, 2001
3,566
3
81
Well here's an interesting bit caught by someone on Usenet - if you reverse (i + u) to (u + i), the splint warning disappears! That does make this look rather like a Splint bug, doesn't it? Cat, perhaps you want to mention this to David, and see what the official response is?
 

Cat

Golden Member
Oct 10, 1999
1,059
0
0
You are using the latest Splint, right? You compiled from the CVS tree?
Edit: Evans has added it to the buglist.
Nice work cleverhandle. :)