skip to Main Content

I can compile and run a program that assigns a long int literal, albeit it one that would fit into an int, to an int variable.

$ cat assign-long-to-int.c
#include <stdio.h>

int main(void){
  int i = 1234L;        //assign long to an int
  printf("i: %dn", i);
  return 0;
}
$ gcc assign-long-to-int.c -o assign-long-to-int
$ ./assign-long-to-int 
i: 1234

I know that 1234 would fit into an int but would still expect to be able to enable a warning. I’ve been through all the gcc options but can’t find anything suitable.

Is it possible to generate a warning for this situation? From the discussion here, and the gcc options, the short answer is no. It isn’t possible.

Would there be any point in such a warning?
It’s obvious in the trivial example I posted that 1234L is being assigned to an int variable, and that it will fit. However, what if the declaration and the assignment were separated by many lines of code? The programmer writing 1234L is signaling that they expect this literal integer to be assigned to a long. Otherwise, what’s the point of appending the L?

In some situations, appending the L does make a difference. For example

$ cat sizeof-test.c 
#include <stdio.h>
void main(void){
  printf("%ldn", sizeof(1234));
  printf("%ldn", sizeof(1234L));
}
$ ./sizeof-test 
4
8

Although the compiler must know that 1234L would fit into a 4 byte int, it puts it into an 8 byte long.

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:hsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.3.0-17ubuntu1~20.04' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-9-HskZEa/gcc-9-9.3.0/debian/tmp-nvptx/usr,hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)

3

Answers


  1. In the case of constants, the compiler can see that the value in question fits into the type being assigned to, so there’s really no point in warning. If the constant was out of range, i.e. 5000000000L, then the compiler will see that and generate a warning.

    What the compiler can do however is warn when an integer type that is not a compile type constant is assigned to a lower type:

    long y = 1;
    int x = y;
    

    If you add the -Wconversion flag (not included in either -Wall or -Wextra), you’ll get this warning:

    x1.c:6:5: warning: conversion to ‘int’ from ‘long int’ may alter its value [-Wconversion]
         int x = y;
    
    Login or Signup to reply.
  2. Compilers should check the value range, not the type of the integer constant. Otherwise we would end up with a lot of whining whenever we initialize a small integer type, since there are no small integer constants smaller than int.

    short i = 32768; does for example yield a warning with clang -Wconstant-conversion but not with gcc. There’s -Wconversion but it’s prone to false positives on either compiler.

    If you want to guard against implicit conversions between various integer types, you should probably use a static analyser instead.

    Login or Signup to reply.
  3. The compiler will automatically convert between most primitive integer types. When you convert from a larger type to a smaller type, I’m pretty sure its a feature of the C language that the number will be truncated.

    For example, the following code will print "0xef":

    #include <stdio.h>
    #include <stdint.h>
    int main() {
      uint32_t x = 0xdeadbeef;
      uint8_t y = x;
      printf("0x%xn", y);
      return 0;
    }
    

    To address your question specifically, I don’t think there is a warning for this behavior, because this conversion is technically a defined feature of the C language.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search