alexfru / SmallerC

Simple C compiler
BSD 2-Clause "Simplified" License
1.35k stars 155 forks source link

Signed warning with constant pointers #3

Closed ghost closed 9 years ago

ghost commented 9 years ago

Hello alexfru, I am having trouble compiling a program with the Smaller C compiler hosted on this GitHub page. When trying to compile a program with a pointer to a constant I get a warning about exceeding the limit of a signed type.

I compiled the Smaller C compiler using gcc 4.8.2 on Linux x64. Using Smaller C with no additional options, I compiled the following code.

#define foo 60000
void start()
{
  void *bar = (void*)foo;
}

This yielded a compiler error: "Constant too big for 16-bit signed type". However the compilation is successful if the constant is in hexadecimal. I would have expect a pointer assignment with an explicit cast to be unsigned.

Is this intended behaviour?

Thanks for your assistance, zerokelvinkeyboard

alexfru commented 9 years ago

This is intended and documented behavior (see section "Limitations and implementation details" in the wiki). Try appending the U suffix, e.g. 60000U.

Elaborating further...

Unsuffixed decimal constants like 60000 normally must be a signed integer type.

When int is 16-bit, 60000 (or anything larger than 32767) doesn't fit into a signed 16-bit int. Therefore the compiler must try the next larger signed int type for the constant. It would be a signed 32-bit (or longer) long int. But in 16-bit mode(l)s (selected with the -seg16t, -seg16, -flat16 options) Smaller C does not (yet) support the type long.

When int is 32-bit, anything larger than 2147483647 would have to either become a signed long (if long is longer than 32 bits) or a signed long long (which is at least 64-bit long and is only supported if the compiler is C99) or an unsigned long (if the compiler is C89/ANSI C compiler). Again, my compiler doesn't (yet) support 64-bit long longs. So, in theory, I could choose C89/ANSI C compiler behavior and make 2147483648 and larger constants to be unsigned long. But that could hide bugs sensitive to the standard version that the compiler implements (btw, you can choose the version with gcc's -std option, e.g. -std=c89 or -std=c99, the default being -std=gnu89, AFAIR, which is somewhere in between the two and includes GNU extensions). I decided to explicitly make this an error.

These are the two reasons for the error.

ghost commented 9 years ago

Good old automatic promotion right? I have had problems with this using gcc in the past. It works pretty well but can become a problem if you want to interface with assembly functions or pass something though va_args.

I'll remember to add 'U' in future to avoid ambiguous syntax.

Thank you for your detailed reply.