2009-03-09 11 views
21

EDYCJA: najwyraźniej niektóre z nich nie są dozwolone/uległy zmianie w różnych standardach C. Dla mojej własnej hipotetycznej korzyści, udawajmy, że używamy gcc test.c bez opcji standardowych lub ostrzegawczych.tablice zero length vs. wskaźniki

W szczególności zajmuję się szczegółami ukrytymi pod maską. Dodałem moje bieżące zrozumienie. Czy mam rację?

char **c1; //Size for a pointer is allocated on the stack. sizeof(c1) == sizeof(void*) 
char *c2[0]; //Nothing is allocated on the stack. sizeof(c2) == 0 

Czy jest jakaś różnica między tymi dwoma przypadkami, których nie znam (poza sizeof)?

struct a { 
    int i; 
    char c[0]; //sizeof(a) is sizeof(int)? a.c == (&i)+1? 
}; 

Jak rozumiem, jest to zazwyczaj używane dla tablic o zmiennej długości na końcu struktur. Ale co z tym, że

Co więcej, jak znany jest adres tablicy o zerowej długości, jeśli miejsce na jego wskaźnik nigdy nie jest przydzielone? Przypuszczam, że w ten sam sposób znany jest adres regularnej tablicy, ale w tej chwili staram się omijać go.

+0

Zobacz także [tutaj] (http://stackoverflow.com/a/14643530/912144). – Shahbaz

Odpowiedz

9

ISO C zabrania 0 -między tablicami.

char **c1; 

Określa obiektu c1 typu wskaźnik do wskaźnik do karbonizatu.

char *c2[0]; 

To jest błąd kompilacji. Nie dozwolony. Nie w C, nie w C++.

struct a { 
    int i; 
    char c[0]; //sizeof(a) is sizeof(int)? a.c == (&i)+1? 
}; 

Błąd opisany wcześniej - rozmiar tablicy musi być większy od zera.

struct a { 
    int i; 
    char c[1]; 
}; 

znany również jako struct-Hack. Nadużywane w kodach niskopoziomowych na prawie wszystkich systemach operacyjnych - Linux, Windows.

C99 ma dać nam sizeless tablicę lepiej znany jako członka elastycznej tablicy:

struct a { 
    int i; 
    char c[]; /* note: no size */ 
}; 
+0

Ahh, ale jeśli przepisałeś go ias char c []; i miał c jako ostatni członek a, byłby legalny od C99. Whee! – MSN

+0

@MSN - dodał, że kilka sekund przed wysłaniem komentarza :) – dirkgently

+0

To nie zawsze jest błąd podczas kompilacji. gcc ostrzega tylko o tym, i to tylko z flagami -Wall i -pedantic. – mkb

12

Jedyny czas jaki kiedykolwiek widziałem tablice zerowej długości rzeczywiście jest używany, gdy chcemy mieć zmienną długość struktury .

jak w tym przykładzie pochodzą z here

struct line { 
     int length; 
     char contents[0]; 
    }; 

    struct line *thisline = (struct line *) 
     malloc (sizeof (struct line) + this_length); 
    thisline->length = this_length; 

Nie chcesz użyć wskaźnika w powyższej struktury, jak chcesz zawartość być część przydzielonej pamięci struktury.

Jeśli zrobisz sizeof na powyższej strukturze, to nie będzie zawierać spacji dla zawartości. Nie jestem pewien, czy kiedykolwiek stał się standardem, daje ostrzeżenia na różnych kompilatorach.

+0

Dziękuję za wyjaśnienie praktycznego zastosowania tego idiomu. Niezależnie od tego, czy jest to słuszne, to nie ma znaczenia, czy ktoś próbuje zrozumieć kod, który z niego korzysta. –

1

od standardu C99 (7.20.3), dotyczących funkcji rozdziału:

Każdy taki przydział uzyskując wskaźnik do rozłącznych obiektu z innym przedmiotem.

[...]

Jeśli wielkość przestrzeni wymagane jest zero, zachowanie jest realizacja zdefiniowane: albo zerowy wskaźnik jest zwracany, lub zachowanie jest jak gdyby wielkość były jednymi wartość niezerową, oprócz tego, że wrócił wskaźnik nie powinien użyj, aby uzyskać dostęp do obiektu.

Innymi słowy, w przypadku zadeklarowania b na stosie bez inicjatora (gdzie b jest nie c zadeklarowane jako c[] zamiast c[0]), rzeczywista wielkość b pod względem przestrzeni faktycznie wykorzystanych będzie> 0, ponieważ nie masz dostępu do żadnej części b. Jeśli zostanie przydzielony przez malloc, zostanie zwrócony jako 0 lub jako pewna unikalna wartość, do której nie można uzyskać dostępu (jeśli używasz sizeof(b)).

+0

Z pewnością ta część normy dotyczy tylko malloc? Nie widzę znaczenia wcześniejszej części tej odpowiedzi. Co oznacza "faktycznie używana przestrzeń będzie> 0, ponieważ nie masz dostępu do żadnej części b" –

2

Możesz uzyskać niektóre odpowiedzi tutaj z GCC docs. Ale to skupia się na temacie posiadania tablicy o zerowej długości jako ostatnich członków struktury. Nie daje bezpośrednich odpowiedzi dotyczących sizeof.

(jak to zostało jasno inni macierze o zerowej długości nie są w standardzie C, ale były w GNU C)

0

Tablica nie może mieć zerową wielkość.

ISO 9899:2011 6.7.6.2: 

If the expression is a constant expression, it shall have a value greater than zero. 

Powyższy tekst dotyczy zarówno zwykłej tablicy (§1), jak i VLA (§5). Jest to tekst normatywny w standardzie C. Kompilator nie może implementować go inaczej.

gcc -std = c99 -pedantic ostrzega o tym.

Powiązane problemy