2013-04-25 4 views
8

Hier ist ein Makro für das Erhalten Array-GrößeC++ die Bedeutung Größe einer Reihe von immer

#define array_size(array) \ 
(sizeof(array)/(sizeof(array[0]) * (sizeof(array) != sizeof(void*) || sizeof(array[0]) <= sizeof(void*))) 

Ich denke, normalerweise (sizeof (array)/(sizeof (array [0])) ist gut genug zu bekommen die Größe des Arrays.

ich denke, den Teil

(sizeof(array[0]) * (sizeof(array) != sizeof(void*) || sizeof(array[0]) <= sizeof(void*)) 

ist das ganze durch Null geteilt zu vermeiden, jemand zu erklären helfen könnte?

Vielen Dank im Voraus.

Cheers,

+0

ich würde vermuten, dass diese zufälligen Missbrauch mit einem verfallenen Zeiger-to-first-Elemente zu verhindern, ist in diesem Fall und Plattform -abhängig hätte dies den Wert "0" ... –

+0

sizeof kann nie ze zurückgeben ro. – john

+6

"ist die ganze Sache durch Null geteilt zu vermeiden" Im Gegensatz dazu ist es eine Division durch Null bei der Kompilierung zu erzwingen, wenn "sizeof Array == sizeof (void *)" und "sizeof array [0]> sizeof (void *) '. –

Antwort

12

sizeof array[0] im Divisor Multipliziert von

(sizeof(array) != sizeof(void*) || sizeof(array[0]) <= sizeof(void*)) 

macht den Divisor Null, wenn

sizeof array == sizeof(void*) 

und

sizeof array[0] > sizeof(void*) 

In diesen Fällen erhalten Sie während der Kompilierung eine Division durch Null, wodurch die Kompilierung fehlschlagen würde.

Diese Überprüfungen sind ein Versuch, Argumente zu erkennen, die Zeiger sind (sei es das Ergebnis von Array-zu-Zeiger-Konvertierung oder nicht), da man nicht wissen kann, wie groß ein "Array" ein Zeiger darauf zeigt Quotient.

Es schlägt fehl, wenn andere Zeigertypen unterschiedliche Größen als void* haben, und es erkennt keine Zeiger auf Dinge, die nicht größer als void* s sind. Es tut wahrscheinlich mehr Schaden als Nutzen, wenn man den Autor in falscher Sicherheit lullt.

+0

Und natürlich ist ein Array von Zeiger völlig legal und dieses Makro wird auf ihm fehlschlagen ... –

1

Ich nehme an, das Teil ist klar: sizeof(array)/sizeof(array[0])

Dieser Teil (sizeof(array) != sizeof(void*) || sizeof(array[0]) <= sizeof(void*)) ein logischer Ausdruck ist, so wahr oder falsch ergibt. Wenn der gesamte Ausdruck berechnet wird, also sizeof(array[0]) mit dem logischen Ausdruck multipliziert wird, konvertiert der Compiler den logischen Ausdruck in 0 oder 1. Sie erhalten also
oder
sizeof(array)/(sizeof(array[0]) * 0).

Der erste Fall ist der normale und gewünschte Fall. Der zweite Fall gibt Ihnen einen Compilerfehler wegen Division durch Null. So wird der Code nicht kompiliert werden, wenn Sie zum Beispiel nennen:

long *p; // assuming a platform with sizeof(long)==sizeof(void*) 
array_size(p); 

Aber es wird nicht Fehler fangen wie:

char *p; 
array_size(p); 

Und es wird für einen Fall nicht kompiliert I'ld es will kompilieren für: BTW

long x[1]; // assuming a platform with sizeof(long)==sizeof(void*) 
array_size(x); 

, wenn Sie diese Funktion als Makro deklarieren (und in C++ I'ld bevorzugen wirklich die Vorlage Stil-Lösung), sollten Sie alle array im Makroändern.

6

Ich denke, normalerweise (sizeof (array)/(sizeof (array [0])) gut genug ist, um die Größe des Arrays zu erhalten.

Obwohl es nicht Ihre primäre Frage, aber Sie erwähnte es die richtige Art und Weise Array-Größe in C++ zu bestimmen, ist mit Hilfe von Vorlagen:..

template<typename T, size_t size> 
constexpr size_t array_size(T(&)[size]){ 
    return size; 
} 
+0

Zusätzlicher Bonus: viel klarere Fehlermeldung, wenn das Argument kein Array ist. Es sollte jedoch "constexpr" sein. – MSalters

+0

Ja, idealerweise sollte es "constexpr" sein. Leider unterstützen viele Compiler, die heute verwendet werden, das nicht, daher habe ich es weggelassen. –

Verwandte Themen