1

Given that C insists on decaying array types into pointers, when passing arrays to functions, then why is it UB to externally link to an array as a pointer?

As an example:

MyFile.c

// Declare and initialize a globally available array of integers
int data[5] = { 10, 15, 20, 21, 22 };

MyFile.h

// Extern the array as a pointer, instead of an int-array
// It *looks* like the array decays to pointer, but is technically UB.
extern int *const data;

Main.c

// Bring in the declaration of data as a const-pointer.
#include "MyFile.h"

int main(void)
{ 
    // Try to set a member of the array. UB!
    data[4] = 0; 

    // Try to use data. Technically UB!
    printf("Value is %d\n", data[4]);

    return 0;
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
mcandre
  • 22,868
  • 20
  • 88
  • 147
  • 1
    It would take very little code for you to provide an example. I edited it in for you. – abelenky Mar 19 '23 at 13:09
  • See answers at [Why this simple program in C crashes (array vs. pointer)](https://stackoverflow.com/questions/46222953). – Steve Summit Mar 19 '23 at 13:13
  • TLDR: Arrays **have** an address that is always valid. Pointers **contain** an address that may or may not be valid. Array decay means a bare, unadorned array **in an expression** is syntactically the same as the **address** if it's first element - IMO it's more correct to say arrays decay to an **address** and not a pointer - a pointer is an lvalue, an address is not. You can assign values to a pointer. You can't assign anything to the address of an array any more than you can assign to the value `5` - it's **not** a "pointer" lvalue. – Andrew Henle Mar 19 '23 at 13:17
  • 1
    In the case of array-to-pointer decay, the compiler knows that you have an array, and knows you're using the array in a context where a pointer value is required. The compiler has complete knowledge, and its knowledge is correct. In the case of a misdeclared array, on the other hand, we have two separate source files, likely compiled by two different invocations of the compiler at two different times, and these files contain inconsistent data — one of them is wrong. There is no way for the compiler to detect, or correct for, that mismatch. An array is not a pointer. – Steve Summit Mar 19 '23 at 13:27

2 Answers2

3

A declaration must match the corresponding definition.

Suppose you had the following definition in one source file:

int x[] = { 1, 2, 3 };

With the following declaration in another:

extern int *x;

In the module where the declaration is visible, it would expect the bytes of x to contain a pointer value but it instead contains the values contained in the array.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • Your declarations are not the same in other ways, as `x = (re-seat address)` is valid for the `extern int`, but makes no sense for the array. The equivalent version would be `extern int *const x;`, saying that `x` is a pointer, but it is a *constant pointer* that cannot be changed to point to a new location. – abelenky Mar 19 '23 at 13:59
2

Arrays and pointers are two different types. Arrays can be implicitly converted to pointers to their first elements in expressions but such a conversion does not take place between two declarations of the same entity. So the compiler will issue an error that an entity is redeclared if the same entity in the same scope will be declared as having different types.

For example imagine if this was possible, then what value shall the operator sizeof return for such an entity? The size of a pointer or the size of an array?

Consider your own code.

// Bring in the declaration of data as a const-pointer.

#include "MyFile.h"

int main(void)
{ 
    // Try to set a member of the array. UB!
    printf( "sizeof( data ) = %zu\n", sizeof( data ) );
    //..

What will be outputted?

The memory occupied by a pointer contains an address. On the other hand, the memory occupied by an array contains array elements.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335