1

In C, you can have an array defined locally on in a struct where the length is known.

eg:

{
    int foo[8];
    assert(sizeof(foo) == sizeof(int[8]));
    ...

When used in a struct, the array size is also known.

struct MyStruct { int foo[8]; };
void func(struct MyStruct *mystruct)
{
    assert(sizeof(mystruct->foo) == sizeof(int[8]));

However when passed as an argument to a function, this is equivalent to an int *.

void func(int foo[8])
{
    assert(sizeof(foo) == sizeof(int[8]));  /* will fail */

This is of course correct and to be expected, my question is - whats the terminology to use when referring to the difference?

eg, what would be the correct completion of this comment?

/* This macro will only work correctly when ____ */
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
ideasman42
  • 42,413
  • 44
  • 197
  • 320

4 Answers4

4

As you said, in C, a pointer to the array is passed to a function, and so you can't find its size using the sizeof operator at all.

The comment is wrong to start with, it should be:

/* This macro will only work correctly if 'a' is an array type */
MByD
  • 135,866
  • 28
  • 264
  • 277
2

Arrays decay into pointers when passed in to functions. The comment might be:

/* This macro will only work correctly when the array is not decayed */
TartanLlama
  • 63,752
  • 13
  • 157
  • 193
  • @juanchopanza: Is it possible to have a function argument thats an array?, The only way I've seen arrays pass-by-value, is by wrapping them into a `struct`. – ideasman42 May 02 '15 at 14:03
  • @ideasman42 You can have functions whose *parameter* is a pointer to array. – juanchopanza May 02 '15 at 14:23
2

Function parameters cannot have array type. The declaration

void func(int foo[8])

is just syntactic sugar for

void func(int *foo)

discarding any size information (except in case of the declaration int foo[static 8] - the type will still be adjusted to int*, but the compiler may use the size information for optimization purposes).

Note that in addition to arrays of statically known size, there are also variable-length arrays of dynamic size and incomplete arrays of unknown size. The latter can only appear in external declarations (as storage requirements are unknown) or within a struct as a flexible array member.

In case of variable-length arrays, sizeof has to be evaluated at runtime, in case of incomplete arrays, it should fail to compile.

So if you want to be specific, your comment could be written as:

This macro will only work correctly when 'a' has complete array type and in particular is not a function parameter as those have pointer type.

Christoph
  • 164,997
  • 36
  • 182
  • 240
  • 1
    Note, even though you dont say it does: using `int foo[static 8]` doesnt change behavior wrt `sizeof`. maybe worth noting for clarity – ideasman42 May 02 '15 at 14:31
  • Also maybe worth linking to: http://stackoverflow.com/questions/3430315/purpose-of-static-keyword-in-array-parameter-of-function – ideasman42 May 02 '15 at 14:33
  • @ideasman42: I explicitly mentioned that *the type will still be adjusted*, but nevertheless I clarified – Christoph May 02 '15 at 17:02
  • Note, you use the phrase *"adjusted to `int`"* but it seems there is a more precise term in this context: **"decay"** - see: http://stackoverflow.com/questions/1461432/what-is-array-decaying – ideasman42 May 02 '15 at 20:23
  • @ideasman42: the C standard defines *adjustment* of parameter types, *promotion* of arguments and operands and *conversion* of lvalues, arrays and function designators; *decay* is a colloquial term for automatic conversion of expressions with array type, which is different from parameter adjustment – Christoph May 02 '15 at 20:43
  • 1
    @ideasman42 No, the terminology is correct here. The function parameter gets *adjusted* to pointer, meaning the function signature is exactly `void func(int *foo)`. An array name passed as *argument* to this function would undergo *decay*. – juanchopanza May 02 '15 at 20:43
  • @juanchopanza, wrt your last comment, This is quite an important distinction and think its worth noting in the answer. – ideasman42 Sep 05 '15 at 08:24
1

/* This macro will only work correctly when "a" is a complete type array */

Because you can not use sizeof with an incomplete type:

struct T {
    int a;
    int arr[]; /* Flexible array */
};

int main(void)
{
    struct T x;

    /* invalid application of ‘sizeof’ to incomplete type ‘int[]’ */    
    printf("%zu\n", ARRAY_SIZE(x.arr)); 
    return 0;
}
ideasman42
  • 42,413
  • 44
  • 197
  • 320
David Ranieri
  • 39,972
  • 7
  • 52
  • 94