Может sizeof вернуть 0 (ноль) - PullRequest
50 голосов
/ 13 апреля 2010

Возможно ли, чтобы оператор sizeof возвращал 0 (ноль) в C или C ++? Если это возможно, правильно ли это с точки зрения стандартов?

Ответы [ 10 ]

40 голосов
/ 13 апреля 2010

В C ++ пустой класс или структура имеет sizeof по крайней мере 1 по определению. Из стандарта C ++, 9/3 «Классы»: «Полные объекты и дочерние подобъекты типа класса должны иметь ненулевой размер.»

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

Это является следствием грамматики (которая требует, чтобы что-то было внутри фигурных скобок) вместе с этим предложением из 6.7.2.1/7 «Спецификаторы структуры и объединения»: «Если список объявляемых структур не содержит именованных членов , поведение не определено ".

Если разрешена структура нулевого размера, то это расширение языка (или недостаток компилятора). Например, в GCC расширение задокументировано в «Структуры без элементов» , в которых говорится:

GCC позволяет структуре C не иметь членов:

 struct empty {
 };

Структура будет иметь нулевой размер. В C ++ пустые структуры являются частью языка. G ++ обрабатывает пустые структуры, как если бы они имели единственный член типа char.

20 голосов
/ 13 апреля 2010

sizeof никогда не возвращает 0 в C и C ++. Каждый раз, когда sizeof оценивается как 0, это ошибка / сбой / расширение определенного компилятора, который не имеет ничего общего с языком.

9 голосов
/ 13 апреля 2010

Каждый объект в C должен иметь уникальный адрес. Иными словами, адрес должен содержать не более одного объекта данного типа (чтобы разыменование указателя работало). При этом рассмотрим «пустую» структуру:

struct emptyStruct {};

и, более конкретно, их массив:

struct emptyStruct array[10];
struct emptyStruct* ptr = &array[0];

Если объекты действительно были пустыми (то есть, если sizeof(struct emptyStruct) == 0), то ptr++ ==> (void*)ptr + sizeof(struct emptyStruct) ==> ptr, что не имеет смысла. К какому объекту тогда относится *ptr, ptr[0] или ptr[1]?

Даже если структура не имеет содержимого, компилятор должен обрабатывать ее так, как если бы она была длиной в один байт, чтобы поддерживать принцип «один адрес, один объект».

Спецификация языка C (раздел A7.4.8) формулирует это требование как

применительно к конструкции или объединению, результат (оператора sizeof) количество байтов в объекте, включая любые отступы, необходимые для объект мозаичный массив

Поскольку байт заполнения должен быть добавлен к «пустому» объекту, чтобы он работал в массиве, sizeof() должен поэтому возвращать значение по крайней мере 1 для любого допустимого ввода.

Edit: Раздел A8.3 спецификации C вызывает структуру без списка членов неполный тип , а определение sizeof специально гласит (с добавлением акцента):

Оператор (sizeof) не может быть применяется к операнду функции типа, или неполного типа , или битовое поле.

Это будет означать, что использование sizeof для пустой структуры будет столь же недействительным, как и использование его для типа данных, который не был определен. Если ваш компилятор допускает использование пустых структур, имейте в виду, что использование sizeof на них не разрешено согласно спецификации C. Если ваш компилятор все равно позволяет вам это делать, помните, что это нестандартное поведение, которое не будет работать на всех компиляторах; не полагайтесь на это поведение.

Редактировать: См. Также эту запись в FAQ Бьярна Страуструпа.

5 голосов
/ 13 апреля 2010

Пустые структуры, как упоминает Исбадави . Также gcc позволяет массивы 0 размера :

int a[0];
sizeof(a);

РЕДАКТИРОВАТЬ: После просмотра ссылки MSDN, я попробовал пустую структуру в VS2005 и sizeof действительно вернул 1. Я не уверен, является ли это ошибкой VS или спецификация как-то гибка в такого рода вещах

2 голосов
/ 13 апреля 2010

, на мой взгляд, лучше, если sizeof возвращает 0 для структуры размера 0 (в духе c). но тогда программист должен быть осторожен, когда он принимает размер пустой структуры.

но это может вызвать проблемы. когда массив таких структур определен, то

& arr [1] == & arr [2] == & arr [0]

, что заставляет их терять свою личность.

Полагаю, это не дает прямого ответа на ваш вопрос, возможно это или нет. хорошо, что может быть возможно в зависимости от компилятора. (как сказано в ответе Майкла выше).

1 голос
/ 14 марта 2013
typedef struct {
  int : 0;
} x;

x x1;
x x2;

Под MSVC 2010 (/ Za / Wall):

sizeof(x) == 4
&x1 != &x2

Под GCC (-ansi -pedantic -Wall):

sizeof(x) == 0
&x1 != &x2

т.е. Хотя в GCC он имеет нулевой размер, экземпляры структуры имеют разные адреса.

ANSI C (C89 и C99 - я не смотрел на C ++) говорит: «Должна быть возможность выразить адрес каждого отдельного байта объекта уникальным образом». Это кажется неоднозначным в случае объекта нулевого размера, поскольку он, возможно, не имеет байтов.

Редактировать: "Объявление битового поля без декларатора, а только двоеточие и ширина, указывает безымянное битовое поле. В особом случае битовое поле с шириной 0 указывает, что больше битовое поле должно быть упаковано в блок, в который было помещено предыдущее битовое поле, если оно есть. "

0 голосов
/ 13 февраля 2017
struct Empty {
} em;

struct Zero {
    Empty a[0];
} zr;

printf("em=%d\n", sizeof(em));
printf("zr=%d\n", sizeof(zr));

Результат:

em=1
zr=0
0 голосов
/ 19 декабря 2015

Если у вас есть это:

struct Foo {}; 
struct Bar { Foo v[]; }

g++ -ansi возвращает sizeof (Bar) == 0. Как и компилятор clang & intel.

Однако, это не компилируется с gcc. Я сделал вывод, что это расширение C ++.

0 голосов
/ 14 апреля 2010

Вот тест, где sizeof дает 0

#include <stdio.h>

void func(int i)
{
        int vla[i];
        printf ("%u\n",(unsigned)sizeof vla);
}


int main(void)
{

        func(0);
        return 0;
}
0 голосов
/ 13 апреля 2010

Я думаю, что он никогда не возвращает 0 в c, пустые структуры не допускаются

...