Kann dieses Makro in eine Funktion umgewandelt werden?

8

Beim Refactoring von Code und dem Entfernen all dieser # Definitionen, die uns jetzt beigebracht werden zu hassen, stieß ich auf diese Schönheit, die zur Berechnung der Anzahl von Elementen in einer Struktur verwendet wurde:

%Vor%

Sehr nützlich wie es ist, aber kann es in eine Inline-Funktion oder eine Vorlage umgewandelt werden?

OK, ARRAYSIZE wäre ein besserer Name, aber das ist Legacy-Code (keine Ahnung, wo es herkommt, es ist mindestens 15 Jahre alt), also habe ich es eingefügt wie es ist.

    
Rob 18.09.2008, 18:40
quelle

16 Antworten

19
___ qstntxt ___

Beim Refactoring von Code und dem Entfernen all dieser # Definitionen, die uns jetzt beigebracht werden zu hassen, stieß ich auf diese Schönheit, die zur Berechnung der Anzahl von Elementen in einer Struktur verwendet wurde:

%Vor%

Sehr nützlich wie es ist, aber kann es in eine Inline-Funktion oder eine Vorlage umgewandelt werden?

OK, ARRAYSIZE wäre ein besserer Name, aber das ist Legacy-Code (keine Ahnung, wo es herkommt, es ist mindestens 15 Jahre alt), also habe ich es eingefügt wie es ist.

    
___ answer95714 ___

Das Makro hat einen sehr irreführenden Namen - der Ausdruck im Makro gibt die Anzahl der Elemente in einem Array zurück, wenn der Name eines Arrays als Makroparameter übergeben wird.

Bei anderen Typen erhalten Sie etwas mehr oder weniger bedeutungsloses, wenn der Typ ein Zeiger ist oder Sie einen Syntaxfehler bekommen.

Normalerweise wird das Makro so benannt wie NUM_ELEMENTS () oder etwas, um seine wahre Nützlichkeit anzuzeigen. Es ist nicht möglich, das Makro durch eine Funktion in C zu ersetzen, aber in C ++ kann eine Vorlage verwendet werden.

Die Version, die ich verwende, basiert auf dem Code in winnt.h von Microsoft (bitte teilen Sie mir mit, ob das Veröffentlichen dieses Snippets über den fairen Gebrauch hinausgeht):

%Vor%

Auch Matthew Wilsons Buch "Imperfect C ++" hat eine schöne Behandlung dessen, was hier vor sich geht (Abschnitt 14.3 - Seite 211-213 - Arrays und Zeiger - dimensionof ()).

    
___ answer95633 ___

Ihr Makro ist falsch benannt, es sollte ARRAYSIZE genannt werden. Es wird verwendet, um die Anzahl der Elemente in einem Array zu ermitteln, deren Größe zur Kompilierungszeit festgelegt ist. Hier ist ein Weg, wie es funktionieren kann:

  

char foo [128]; // In Wirklichkeit würdest du   habe etwas konstant oder konstant   Ausdruck als Array-Größe.

     

für (vorzeichenlos i = 0; i & lt; STRUKTUR (   foo); ++ i) {}

Es ist etwas spröde zu benutzen, weil Sie diesen Fehler machen können:

  

char * foo = neues Zeichen [128];

     

für (vorzeichenlos i = 0; i & lt; STRUKTUR (   foo); ++ i) {}

Sie werden jetzt für i = 0 zu & lt; 1 und reiß dein Haar aus.

    
___ answer95664 ___

Der Typ einer Template-Funktion wird automatisch abgeleitet, im Gegensatz zu dem einer Template-Klasse. Sie können es noch einfacher verwenden:

%Vor%

Aber ich stimme zu, es funktioniert nicht für Strukturen: Es funktioniert für Arrays. Also würde ich es eher als Arraygröße bezeichnen:)

    
___ answer97523 ___

Die Lösung von KTC ist zwar sauber, kann aber nicht zur Kompilierzeit verwendet werden und ist vom Compiler abhängig Optimierung, um Code-Bloat- und Funktionsaufruf-Overhead zu verhindern.

Man kann die Array-Größe mit einer Compile-Time-Only-Metafunktion ohne Laufzeitkosten berechnen. BCS war auf dem richtigen Weg, aber diese Lösung ist falsch.

Hier ist meine Lösung:

%Vor%

mit Testcode (mit Boost.StaticAssert , um die Kompilierzeit zu demonstrieren -nur Verwendung):

%Vor%

Diese Lösung weist bei der Kompilierung keine Array-Typen zurück, so dass sie nicht durch Zeiger verwechselt werden, wie dies bei der Makroversion der Fall ist.

    
___ answer96085 ___

Simplfying @ KTC's, da wir die Größe des Arrays im Template-Argument haben:

%Vor%

Nachteil ist, dass Sie eine Kopie davon in Ihrer Binärdatei für jede Typname, Größenkombination haben werden.

    
___ answer95518 ___
  • Funktion, keine Template-Funktion, ja
  • Vorlage, ich denke schon (aber C ++
  • Vorlagen sind nicht mein Ding)

Bearbeiten: Aus Dougs Code

%Vor%

Mir wurde gesagt, dass der zweite nicht funktioniert. OTOH etwas wie es sollte machbar sein, ich benutze nur C ++ nicht genug, um es zu beheben.

Eine Seite mit C ++ - (und D-) Vorlagen für die Kompilierzeit

    
___ answer98059 ___

Ich bevorzuge die von [BCS] vorgeschlagene Enum-Methode (in Kann dieses Makro in eine Funktion umgewandelt werden? )

Dies liegt daran, dass Sie es dort verwenden können, wo der Compiler eine Kompilierzeitkonstante erwartet. Die aktuelle Version der Sprache lässt Sie keine Funktionsergebnisse für Kompilierzeitkonstraste verwenden, aber ich glaube, das kommt in der nächsten Version des Compilers:

Das Problem mit dieser Methode ist, dass es keinen Kompilierzeitfehler erzeugt, wenn es mit einer Klasse verwendet wird, die den '*' Operator überladen hat (Details siehe unten).

Leider kompiliert die von 'BCS' bereitgestellte Version nicht so wie erwartet, also hier ist meine Version:

%Vor%     
___ answer95550 ___

Ich glaube nicht, dass das wirklich die Anzahl der Elemente in einer Struktur berechnet. Wenn die Struktur gepackt ist und Sie Objekte verwenden, die kleiner sind als die Zeigergröße (z. B. char auf einem 32-Bit-System), sind die Ergebnisse falsch. Wenn die Struktur eine Struktur enthält, irren Sie sich auch!

    
___ answer95521 ___

Ja, es kann eine Vorlage in C ++ gemacht werden

%Vor%

zu verwenden:

%Vor%

Siehe BCS Beitrag oben oder unten über eine coole Möglichkeit, dies mit einer Klasse zur Kompilierzeit zu tun, indem Sie eine leichte Template-Metaprogrammierung verwenden.

    
___ answer96227 ___

Wie John McG's Antwort, aber

Nachteil ist, dass Sie eine Kopie davon in Ihrer Binärdatei für jede Kombination von Typname und Größe haben werden.

Aus diesem Grund sollten Sie eine Inline Vorlagenfunktion erstellen.

    
___ answer96038 ___

xtofl hat die richtige Antwort, um eine Array-Größe zu finden. Zum Ermitteln der Größe einer Struktur sollte kein Makro oder Template benötigt werden, da sizeof () gut funktionieren sollte.

Ich stimme dem Präprozessor zu, ist böse , aber es gibt Gelegenheiten, wo es ist ist das kleinste Übel der Alternativen .

    
___ qstnhdr ___ Kann dieses Makro in eine Funktion umgewandelt werden? ___ answer100495 ___

Windows-spezifisch:

Das Makro %code% wird vom CRT genau für diesen Zweck geliefert.

Ein Link zum Dokument bei MSDN

    
___ answer96291 ___

Beantwortete im Detail hier: Array-Größenbestimmung Teil 1 und hier: Array-Größenbestimmung Teil 2 .

    
___ tag123c ___ C ++ ist eine universelle Programmiersprache. Es wurde ursprünglich als Erweiterung von C entworfen und behält eine ähnliche Syntax, ist aber jetzt eine komplett andere Sprache. Verwenden Sie dieses Tag für Fragen zu Code, der mit einem C ++ - Compiler kompiliert werden soll. ___ tag123macros ___ *** NICHT für VBA / MS-Office-Sprachen verwenden. Verwenden Sie stattdessen die entsprechenden [vba] -Tags. *** Ein Makro ist eine Regel oder ein Muster, das angibt, wie eine bestimmte Eingabesequenz (oft eine Folge von Zeichen) einer Ausgabesequenz (oft auch eine Folge von Zeichen) gemäß einer definierten Prozedur zugeordnet werden soll. ___ tag123cpreprocessor ___ Der Makrovorverarbeitungsschritt der Programmiersprachen C und C ++. Dieser Tag kann auch für Fragen zu anderen Compilern / Sprachen verwendet werden, die von identischen Funktionen abgeleitet sind oder diese enthalten, wie z. B. die #Direktiven in Objective-C oder C #. ___ answer175209 ___

Für C99-artige Arrays variabler Länge scheint es, dass der reine Makro-Ansatz (sizeof (arr) / sizeof (arr [0])) der einzige ist, der funktioniert.

    
___ answer100872 ___

Keiner hat bisher einen portablen Weg vorgeschlagen, um die Größe eines Arrays zu erhalten, wenn Sie nur eine Instanz eines Arrays und nicht seinen Typ haben. (typeof und _countof sind nicht tragbar, können also nicht verwendet werden.)

Ich würde es folgendermaßen machen:

%Vor%
  • Es funktioniert, wenn nur der Wert vorhanden ist.
  • Es ist portabel und verwendet nur std-C ++.
  • Es schlägt mit einer deskriptiven Fehlermeldung fehl.
  • Es wird der Wert nicht ausgewertet. (Ich kann mir keine Situation ausdenken, in der dies ein Problem wäre, da der Array-Typ von einer Funktion nicht zurückgegeben werden kann, aber sei besser als Nachsicht.)
  • Gibt die Größe als Compiletime-Konstante zurück.

Ich habe das Konstrukt in ein Makro eingepackt, um eine anständige Syntax zu erhalten. Wenn Sie es loswerden wollen, ist Ihre einzige Option, die Ersetzung manuell zu tun.

    
___
KTC 18.09.2008, 19:15
quelle
5

Keiner hat bisher einen portablen Weg vorgeschlagen, um die Größe eines Arrays zu erhalten, wenn Sie nur eine Instanz eines Arrays und nicht seinen Typ haben. (typeof und _countof sind nicht tragbar, können also nicht verwendet werden.)

Ich würde es folgendermaßen machen:

%Vor%
  • Es funktioniert, wenn nur der Wert vorhanden ist.
  • Es ist portabel und verwendet nur std-C ++.
  • Es schlägt mit einer deskriptiven Fehlermeldung fehl.
  • Es wird der Wert nicht ausgewertet. (Ich kann mir keine Situation ausdenken, in der dies ein Problem wäre, da der Array-Typ von einer Funktion nicht zurückgegeben werden kann, aber sei besser als Nachsicht.)
  • Gibt die Größe als Compiletime-Konstante zurück.

Ich habe das Konstrukt in ein Makro eingepackt, um eine anständige Syntax zu erhalten. Wenn Sie es loswerden wollen, ist Ihre einzige Option, die Ersetzung manuell zu tun.

    
Ben Strasser 19.09.2008 10:06
quelle
5

Die Lösung von KTC ist zwar sauber, kann aber nicht zur Kompilierzeit verwendet werden und ist vom Compiler abhängig Optimierung, um Code-Bloat- und Funktionsaufruf-Overhead zu verhindern.

Man kann die Array-Größe mit einer Compile-Time-Only-Metafunktion ohne Laufzeitkosten berechnen. BCS war auf dem richtigen Weg, aber diese Lösung ist falsch.

Hier ist meine Lösung:

%Vor%

mit Testcode (mit Boost.StaticAssert , um die Kompilierzeit zu demonstrieren -nur Verwendung):

%Vor%

Diese Lösung weist bei der Kompilierung keine Array-Typen zurück, so dass sie nicht durch Zeiger verwechselt werden, wie dies bei der Makroversion der Fall ist.

    
jwfearn 23.05.2017 12:30
quelle
2

Das Makro hat einen sehr irreführenden Namen - der Ausdruck im Makro gibt die Anzahl der Elemente in einem Array zurück, wenn der Name eines Arrays als Makroparameter übergeben wird.

Bei anderen Typen erhalten Sie etwas mehr oder weniger bedeutungsloses, wenn der Typ ein Zeiger ist oder Sie einen Syntaxfehler bekommen.

Normalerweise wird das Makro so benannt wie NUM_ELEMENTS () oder etwas, um seine wahre Nützlichkeit anzuzeigen. Es ist nicht möglich, das Makro durch eine Funktion in C zu ersetzen, aber in C ++ kann eine Vorlage verwendet werden.

Die Version, die ich verwende, basiert auf dem Code in winnt.h von Microsoft (bitte teilen Sie mir mit, ob das Veröffentlichen dieses Snippets über den fairen Gebrauch hinausgeht):

%Vor%

Auch Matthew Wilsons Buch "Imperfect C ++" hat eine schöne Behandlung dessen, was hier vor sich geht (Abschnitt 14.3 - Seite 211-213 - Arrays und Zeiger - dimensionof ()).

    
Michael Burr 18.09.2008 18:58
quelle
1

Ihr Makro ist falsch benannt, es sollte ARRAYSIZE genannt werden. Es wird verwendet, um die Anzahl der Elemente in einem Array zu ermitteln, deren Größe zur Kompilierungszeit festgelegt ist. Hier ist ein Weg, wie es funktionieren kann:

  

char foo [128]; // In Wirklichkeit würdest du   habe etwas konstant oder konstant   Ausdruck als Array-Größe.

     

für (vorzeichenlos i = 0; i & lt; STRUKTUR (   foo); ++ i) {}

Es ist etwas spröde zu benutzen, weil Sie diesen Fehler machen können:

  

char * foo = neues Zeichen [128];

     

für (vorzeichenlos i = 0; i & lt; STRUKTUR (   foo); ++ i) {}

Sie werden jetzt für i = 0 zu & lt; 1 und reiß dein Haar aus.

    
Don Neufeld 18.09.2008 18:51
quelle
1

Der Typ einer Template-Funktion wird automatisch abgeleitet, im Gegensatz zu dem einer Template-Klasse. Sie können es noch einfacher verwenden:

%Vor%

Aber ich stimme zu, es funktioniert nicht für Strukturen: Es funktioniert für Arrays. Also würde ich es eher als Arraygröße bezeichnen:)

    
xtofl 18.09.2008 18:54
quelle
1

Simplfying @ KTC's, da wir die Größe des Arrays im Template-Argument haben:

%Vor%

Nachteil ist, dass Sie eine Kopie davon in Ihrer Binärdatei für jede Typname, Größenkombination haben werden.

    
JohnMcG 18.09.2008 19:32
quelle
1
  • Funktion, keine Template-Funktion, ja
  • Vorlage, ich denke schon (aber C ++
  • Vorlagen sind nicht mein Ding)

Bearbeiten: Aus Dougs Code

%Vor%

Mir wurde gesagt, dass der zweite nicht funktioniert. OTOH etwas wie es sollte machbar sein, ich benutze nur C ++ nicht genug, um es zu beheben.

Eine Seite mit C ++ - (und D-) Vorlagen für die Kompilierzeit

    
BCS 18.09.2008 18:42
quelle
1

Ich bevorzuge die von [BCS] vorgeschlagene Enum-Methode (in Kann dieses Makro in eine Funktion umgewandelt werden? )

Dies liegt daran, dass Sie es dort verwenden können, wo der Compiler eine Kompilierzeitkonstante erwartet. Die aktuelle Version der Sprache lässt Sie keine Funktionsergebnisse für Kompilierzeitkonstraste verwenden, aber ich glaube, das kommt in der nächsten Version des Compilers:

Das Problem mit dieser Methode ist, dass es keinen Kompilierzeitfehler erzeugt, wenn es mit einer Klasse verwendet wird, die den '*' Operator überladen hat (Details siehe unten).

Leider kompiliert die von 'BCS' bereitgestellte Version nicht so wie erwartet, also hier ist meine Version:

%Vor%     
Martin York 18.09.2008 23:39
quelle
0

Ich glaube nicht, dass das wirklich die Anzahl der Elemente in einer Struktur berechnet. Wenn die Struktur gepackt ist und Sie Objekte verwenden, die kleiner sind als die Zeigergröße (z. B. char auf einem 32-Bit-System), sind die Ergebnisse falsch. Wenn die Struktur eine Struktur enthält, irren Sie sich auch!

    
Ray Hayes 18.09.2008 18:44
quelle
0

Ja, es kann eine Vorlage in C ++ gemacht werden

%Vor%

zu verwenden:

%Vor%

Siehe BCS Beitrag oben oder unten über eine coole Möglichkeit, dies mit einer Klasse zur Kompilierzeit zu tun, indem Sie eine leichte Template-Metaprogrammierung verwenden.

    
Doug T. 18.09.2008 18:42
quelle
0

xtofl hat die richtige Antwort, um eine Array-Größe zu finden. Zum Ermitteln der Größe einer Struktur sollte kein Makro oder Template benötigt werden, da sizeof () gut funktionieren sollte.

Ich stimme dem Präprozessor zu, ist böse , aber es gibt Gelegenheiten, wo es ist ist das kleinste Übel der Alternativen .

    
Fred Larson 18.09.2008 19:28
quelle
0

Wie John McG's Antwort, aber

Nachteil ist, dass Sie eine Kopie davon in Ihrer Binärdatei für jede Kombination von Typname und Größe haben werden.

Aus diesem Grund sollten Sie eine Inline Vorlagenfunktion erstellen.

    
fizzer 18.09.2008 19:49
quelle
0

Beantwortete im Detail hier: Array-Größenbestimmung Teil 1 und hier: Array-Größenbestimmung Teil 2 .

    
heifner 18.09.2008 19:59
quelle
0

Windows-spezifisch:

Das Makro _countof() wird vom CRT genau für diesen Zweck geliefert.

Ein Link zum Dokument bei MSDN

    
shoosh 19.09.2008 08:30
quelle
0

Für C99-artige Arrays variabler Länge scheint es, dass der reine Makro-Ansatz (sizeof (arr) / sizeof (arr [0])) der einzige ist, der funktioniert.

    
Josh Kelley 06.10.2008 17:03
quelle

Tags und Links