Fragen? Antworten! Siehe auch: Alternativlos
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))Wer den auf Anhieb versteht, sollte sich direkt erschiessen, weil er zu viel C gemacht hat.
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) \
+ + sizeof(typeof(int[1 - 2*!!__builtin_types_compatible_p(typeof(arr), \
+ typeof(&arr[0]))]))*0)
Für die anderen erkläre ich es kurz.
ARRAY_SIZE hat vorher die Anzahl der Elemente im Array zurück geliefert, und tut es auch danach. Man sieht, dass der Patch einen komplizierten Ausdruck *0 addiert, also immer Null.
Der einzige Sinn des komplizierten Ausdrucks ist, einen Compile-Zeit-Fehler zu produzieren, wenn __builtin_types_compatible_p 1 zurück liefert. Wenn da 0 rauskommt, macht er zweimal !, das logische NOT, d.h. wieder 0, mal 2 bleibt null, und er hat ein Array der Größe 1, das ist in Ordnung. Wenn da was anderes als 0 rauskommt, macht er zweimal !, d.h. 1, mal 2 ist 2, und damit ist die Arraygröße -1, d.h. negativ, und es ergibt einen Compile-Zeit-Fehler.
Anders formuliert: der Patch ändert das Makro so, dass es zur Compilezeit in die Luft fliegt, wenn man einen anderen Typen als ein Array übergibt, bei dem trotzdem [0] erlaubt ist, also mit anderen Worten einen Pointer.
Kleiner Insider-Joke: früher hat man das ohne 2* gemacht, da war es nämlich in C nicht erlaubt, ein Array mit Null Elementen zu deklarieren. Das hat sich kürzlich geändert, daher steht da jetzt 2*.
Wer das furchtbar findet, sollte von C++ weiträumig Abstand halten.
Der Autor des Hacks ist übrigens Rusty Russell, der u.a. an den module_init_tools und netfilter Verantwortung trägt.
Oh übrigens: __builtin_types_compatible_p ist eine gcc-Erfindung.