1

Is ARRAY_SIZE return undefined behaviour when the array is empty? because we make a devide of unexisting sizeof((X)[0])

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(X) sizeof((X))/sizeof((X)[0])
#endif

struct ka {
    int a;
    int b;
};

int main(void)
{
    struct ka k[] = {};
    printf("%d\n", ARRAY_SIZE(k));
}
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
MOHAMED
  • 41,599
  • 58
  • 163
  • 268
  • 4
    This is not C++. Empty initializer is forbidden for array with unspecified bound – mpiatek Feb 20 '17 at 09:45
  • This is not UB since `sizeof(k[0])` does not actually access any memory. It is exactly the same as `sizeof(ka)` – rustyx Feb 20 '17 at 09:52

2 Answers2

3

It is not possible to have zero-sized arrays in Standard C or C++.

In C your code is a constraint violation (empty initializer lists are not permitted anywhere).

In C++ it is also an error; {} may not be used with an array definition that omits the size. (C++14 [dcl.init.aggr]/4)

If you use a non-standard compiler extension then the behaviour will depend on the details of that extension.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • I build with gcc and it does not return error for C neither a warning – MOHAMED Feb 20 '17 at 09:48
  • 2
    Why is it a divide by zero error? `sizeof((X)[0])` is `sizeof(struct ka)`, which is not `0`. – mch Feb 20 '17 at 09:49
  • 1
    @MOHAMED gcc defaults to GNU extensions mode. Use compile switches `-std=c11 -pedantic` for C, or `std=c++14 -pedantic` for C++ to get standard behaviour. – M.M Feb 20 '17 at 09:49
  • @mch good point ... fixed – M.M Feb 20 '17 at 09:50
1

In general, from the point of view for memory access, this is fine, because, unless the operand of sizeof is of VLA type, they are not evaluated. So, in this case, x[0] is not an invalid memory access.

Quoting C11, chapter §6.5.3.4, emphasis mine

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.

In a broad sense, for an array like

 int arr[5]= {0};

writing

 sizeof(arr)/sizeof(arr[10]);

is also valid as arr[10] is not being evaluated, it's only about the size of the operand, not the content (so, needs no dereferencing).

That said,

  • zero-length arrays are not standard C, they are gcc extension.
  • sizeof yields a results of size size_t, so we should use %zu format specifier to print the result.
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261