2

If I index an array with an unsigned int or a long, is it being implicitly cast into an int, or is the type somehow maintained? If I use large unsigned int as index, is it cast into a negative int? Is this defined behavior or another one of those compiler-can-do-what-it-wants quirks?

6
  • While not authoritative, this subscript reference say that any expression with an integer type is valid. Due to definition of the subscript operation, negative indexes are valid and sometimes used, so it's not possible to limit to unsigned types. But with all this said, whatever integer type you use, the actual value of that type should be used. Commented Oct 8, 2024 at 5:25
  • 1
    Array indexing syntax is really just a convenience. Both a[i] and i[a] are equivalent to *(a+i). So the question really is about pointer addition, which is the addition of a pointer type and an integer type. Commented Oct 8, 2024 at 5:45
  • Please note that no such thing as "implicit cast" exists. C has implicit or explicit conversions. A cast is always an explicit conversion with the ( ) cast operator. Commented Oct 8, 2024 at 6:44
  • Related stackoverflow.com/questions/9386979/…. While implementation defined, the implementation will normally be defined to support the target platform capability. The second ranked answer there is probably more relevant (and accurate) than the first, but is empirical in nature not perhaps definitive. Commented Oct 8, 2024 at 7:19
  • 1
    "compiler-can-do-what-it-wants quirks" is not a fair description of either implementation defined behaviour or undefined behaviour. Implementation defined behaviour is still well defined, and undefined behaviour is normally the result of doing nothing rather than anything - the result of that may be non-deterministic. Commented Oct 8, 2024 at 7:19

2 Answers 2

6

Since arr[i] is per definition equivalent to *((arr) + (i)), the rules for pointer arithmetic is found below the additive operators +, - in the C standard.

C17 6.5.6:

Constraints
For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to a complete object type and the other shall have integer type.

Everywhere in the following text, the term integer type is used. Meaning that any integer type can be use and there are no implicit promotions.

Save for the special scenario where we subtract one pointer from another, in which case the result is the integer type ptrdiff_t.

C specifies no relation between integer types and pointers, likely for the reason that on a traditional computer, there's not necessarily any relation between the CPU data word size and the address bus width. But the C standard doesn't even say or mandate that pointers equal addresses.

The exact nature, width and ranges of the underlying addresses are beyond the scope of the C language and therefore entirely implementation-defined.

Sign up to request clarification or add additional context in comments.

Comments

1

Concerning array and not pointer access:

If I index an array with an unsigned int or a long, is it being implicitly cast into an int, or is the type somehow maintained?

The index is not implicitly cast.
There is no type maintained after the access concerning the index.

// Even though 123 is an `int`, indexes are not limited to type `int`
some_type arr[123];      
unsigned int ui = tbd;   // arr[ui] valid if ui in the [0...122] range.
unsigned long lo = tbd;  // arr[ui] valid if lo in the [0...122] range.

If I use large unsigned int as index, is it cast into a negative int?

No. Still the value of the index must be in the valid range. E.g. [0...122] in above example.


Is this defined behavior or another one of those compiler-can-do-what-it-wants quirks?

Array byte sizes are limited to [1 ... SIZE_MAX]. An allocated array may be larger.

Array indexes are limited to [0 ... SIZE_MAX-1].

SIZE_MAX is at least 65535.

Some system may impose additional limits.


With a pointer the indexing limits apply to the target object.

some_type arr[123];      
some_type *ptr = &arr[1];
int i = tbd;       // ptr[i] valid if i in the [-1...121] range.
unsigned u = tbd;  // ptr[u] valid if u in the [ 0...121] range.
// ptr[(unsigned)-1]` is not valid.

2 Comments

Regarding SIZE_MAX that's apparently just an upper limit and the actual maximum size might come as a surprise. Why is the maximum size of an array "too large"?
@Lundin Fair point. Link added in answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.