Существует известная схема вычисления длины массива:
int arr[10];
size_t len = sizeof(arr) / sizeof(arr[0]);
assert(len == 10);
Этот шаблон применяется к статическим массивам и автоматическим массивам постоянного размера. Это также относится к массивам переменной длины в C99.
Я хочу применить аналогичную идею для вычисления размера динамического массива в байтах:
size_t known_len = 10;
int *ptr = malloc(known_len * sizeof(int));
size_t size = known_len * sizeof(ptr[0]);
assert(size == known_len * sizeof(int));
Это лучше, чем known_len * sizeof(int)
, потому что sizeof(ptr[0])
не относится к типу элемента массива. Следовательно, это не требует, чтобы считыватель кода знал тип.
Однако мне непонятно, может ли выражение sizeof(ptr[0])
привести к поведению undefined. Поскольку он расширен:
sizeof(ptr[0]) -> sizeof(*((ptr) + (0))) -> sizeof(*ptr)
Выражение результата сомнительно, если ptr
равно 0
:
sizeof(*((int*) 0))
В соответствии со стандартом C99:
(C99, 6.3.2.3p3): "Целочисленное постоянное выражение со значением
0
, или такое выражение, которое применяется к типуvoid *
, называется нулевым указателем константа". Отмена нулевого указателя имеет поведение undefined.(C99, 6.5.3.2.p4) "Если недопустимое значение было присвоено указатель, поведение унарного оператора
*
undefined.87)"87): "Среди недопустимых значений для разыменования указателя Унарный оператор
*
- это нулевой указатель, неправильный адрес выровненный для типа объекта, на который указывает, и адрес объект после окончания его жизни."
Но он никогда не указывал, может ли sizeof такого выражения привести к поведению undefined. Фактически такой sizeof следует оценивать во время компиляции.
Мои вопросы:
- Можно ли использовать выражение
sizeof(ptr[0])
в коде, когда типptr
известен, а значениеptr
неизвестно? - Может ли такое использование быть оправданным в соответствии со стандартом C99? Спецификация GNU GCC?