Комментарии 17
Компилятор MSVC не умеет заглядывать внутрь constexpr функций и подставлять значение.
Поэтому тут компилятор не видит проблемы
int a[10];
unsigned char x = 10 + (sizeof(a) / sizeof(a[0]));
// и даже так
constexpr size_t a_number_of_elements = sizeof(a) / sizeof(a[0]);
unsigned char y = 10 + a_number_of_elements
А здесь видит уменьшение размера size_t => unsigned char
int a[10];
unsigned char x = 10 + std::size(a);
int b1[0];
Помнится, данное объявление порой использовалось когда-то в С++ (но уже не припомню, в какой именно реализации С++) в структурах для обозначения произвольных данных неопределенной длины (от нуля и больше) в конце структуры.
И оно даже работало.
Компилятор выдаёт предупреждение, если это окажется не последнее поле в структуре. В том числе при наследовании.
struct S
{
int x;
int z[];
};
Действительно компилируется, предупреждение Warning C4200 nonstandard extension used: zero — sized array in struct / union
Но память под такой массив не выделяется. Попытка доступа компилируется, но при выполнении ошибка: выход за границу стека. При попытке сделать такую структуру базовой или членом возникает ошибка. Не понятно, как это можно использовать (ну может быть только в union).
Раньше это обычно использовали для обработки потоков данных, предваряемых заголовочными структурами, примерно так: получали откуда-то буфер (чтение из файла, вызов функции) и присваивали указатель на него указателю на структуру. Или наоборот, указателю на структуру выделяли требуемую память, а потом ее подсовывали в качестве буфера какой-нибудь функции, это дело заполняющей.
Если память не изменяет, подобный фокус применялся даже в заголовочных файлах библиотеки какой-то СУБД.
Иногда использовали грязный хак, когда за структурой (или даже за массивом нулевой длины) объявляли различные переменные, и обращались потом к ним как к массиву байт. Понятно, что это UB, и оно работало стабильно корректно только при отключенной оптимизации и только в некоторых компиляторах.
#include <stdio.h>
struct A { int x=1; };
struct B : A { int y=2; };
int main() {
A* a=new B[2];
printf("%d %d\n",a[0].x,a[1].x);
delete[] a;
return 0;
}
// outputs: 1 2
std::array<int, 4> a{1, 2, 3, 4};
C++17 позволяет проще:
std::array a{1, 2, 3, 4};
См. en.cppreference.com/w/cpp/language/class_template_argument_deduction
К сожалению, std::array не полностью аналогичен массиву C.
Размер std::array может быть больше аналогичного массива C, потому как это структура и можем иметь дополнительное выравнивание.
std::array всем хорош, кроме конструкции многомерного массива - вот там нечитаемо получается.
Массивы в C++