1

When compiling C for a platform where int and long are both 32 bits, and long long is 64 bit (like clang or gcc -m32 or clang's wasm32-unknown-wasi target), I get errors about incompatible pointer types:

int32_t *i1 = NULL;
long *l1 = i1;
int64_t *i2 = NULL;
long *l2 = i2;
sizeof.c:13:11: warning: incompatible pointer types initializing 'long *' with an expression of type 'int32_t *' (aka 'int *') [-Wincompatible-pointer-types]
    long *l1 = i1;
          ^    ~~
sizeof.c:15:11: warning: incompatible pointer types initializing 'long *' with an expression of type 'int64_t *' (aka 'long long *') [-Wincompatible-pointer-types]
    long *l2 = i2;
          ^    ~~
2 warnings generated.

I find it strange, that neither int32_t nor int64_t is compatible with long. Why is there a warning if int and long are the same?

corvus_192
  • 362
  • 4
  • 15

2 Answers2

1

C’s rules about what makes types compatible are partly about the “meaning” of the type, not just how big it is, what values it represents, or how it represents them. In these rules pointers to int and long are different and incompatible types even if they use the same number of bytes and encode addresses in the same way and point to int and long that use the same number of bytes and encode numbers in the same way.

The C standard may permit a C implementation to defined (by typedef) int32_t and int64_t to be int, long, or long long, as appropriate. In this case the corresponding types would be not just compatible but identical. However the standard also permits them to be defined as extended types, distinct from the basic integer types even if they function identically. As chqrlie notes, your C implementation likely defines int32_t to be int and int64_t to be long long, and so neither is compatible with long.

The “meaning” of the type involves some things about what humans plan to use the type for and what it means to the compiler. int originally meant a size good with the target processor in some sense, but that has been weakened over time. Two structure types might be defined with identical elements, but one contains x-y coordinates for a two-dimensional graph and the other contains real-imaginary parts for complex numbers. Having these be separate and incompatible types helps programmers avoid some errors.

By and large, code such as int32_t x; int *p = &x; was written in error, and a warning is desirable to point that out. And the warning is no hindrance as it is easy to write code that functions as desired without getting the warning.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Thanks, that cleared up a lot. I didn't know that they are treated different even if they are the same size. – corvus_192 Apr 09 '20 at 20:51
1

The reason long * is compatible with neither int32_t * nor int64_t * if these types are defined this way on your platform:

typedef int int32_t;
typedef long long int int64_t;

The standard types int, long and long long are different even if they have the same size and/or representation.

There is nothing in the C Standard that mandates which of int, long and long long should be used for specified size integers, provided one of them matches its number of bits and two's complement representation requirements. int32_t could even be defined as a separate extended type with the appropriate ranking.

You must use the proper pointer types in your code and avoid assumptions on actual representation of the basic integer types.

chqrlie
  • 131,814
  • 10
  • 121
  • 189