2017-02-20 2 views
1

Является ли ARRAY_SIZE возвратом неопределенного поведения, когда массив пуст? потому что мы делаем разделим из unexisting sizeof((X)[0])Возвращает ли ARRAY_SIZE неопределенное поведение, когда массив пуст?

#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)); 
} 
+4

Это не C++. Пустой инициализатор запрещен для массива с неопределенной привязкой – mpiatek

+0

Это не UB, так как 'sizeof (k [0])' фактически не обращается к какой-либо памяти. Это точно так же, как 'sizeof (ka)' – rustyx

ответ

3

Это не возможно иметь нулевого размера массивов в стандартном C или C++.

В C ваш код является нарушением ограничения (пустые списки инициализаторов нигде не разрешены).

В C++ это также ошибка; {} не может использоваться с определением массива, которое не учитывает размер. (C++ 14 [dcl.init.aggr]/4)

Если вы используете нестандартное расширение компилятора, поведение будет зависеть от деталей этого расширения.

+0

Я строю с gcc и не возвращает ошибку для C ни предупреждение – MOHAMED

+2

Почему это деление на нулевую ошибку? 'sizeof ((X) [0])' is 'sizeof (struct ka)', который не является '0'. – mch

+1

@MOHAMED gcc по умолчанию используется режим расширений GNU.Используйте компиляционные ключи '-std = c11 -pedantic' для C, или' std = C++ 14 -pedantic' для C++, чтобы получить стандартное поведение. –

1

В общем, с точки зрения доступа к памяти это нормально, потому что, если операнд sizeof имеет тип VLA, это не оценено. Таким образом, в этом случае x[0] не является недопустимым доступом к памяти.

Цитирование C11, глава §6.5.3.4, курсив мой

Оператор sizeof дает размер (в байтах) своего операнда, который может быть выражение в скобках или имя типа , Размер определяется по типу операндом. Результат - целое число. Если тип операнда является массивом переменной длины , операнд оценивается; в противном случае операнд не оценивается, а результат - целочисленная константа .

В широком смысле, для массива, как

int arr[5]= {0}; 

написание

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

также действует в arr[10] не оценивается, это только о размере операнда , а не содержание (так что не требует разыменования).

Тем не менее,

  • нулевой длины массивы не являются стандартными С, они являются gcc extension.
  • sizeof дает результаты по размеру size_t, поэтому мы должны использовать спецификатор формата %zu для печати результата.
+0

Что оценивается в этом отношении –

+1

@ M.M разыменовывает недопустимую память? –

+0

О, я вижу, он был обеспокоен тем, что x [0] может быть доступным вне пределов доступа. –

Смежные вопросы