Is het mogelijk om de grootte van een C++-klasse af te drukken tijdens het compileren?

Is het mogelijk om de grootte van een C++-klasse te bepalen tijdens het compileren?

Ik meen me een meta-programmeermethode voor sjablonen te herinneren, maar ik kan me vergissen…


sorry dat ik niet duidelijker ben – ik wil dat het formaat wordt afgedrukt in het build-uitvoervenster


Antwoord 1, autoriteit 100%

Als het echt nodig is om sizeof(X) in de uitvoer van de compiler te krijgen, kun je het gebruiken als parameter voor een onvolledig sjabloontype:

template<int s> struct Wow;
struct foo {
    int a,b;
};
Wow<sizeof(foo)> wow;
$ g++ -c test.cpp
test.cpp:5: error: aggregate ‘Wow<8> wow’ has incomplete type and cannot be defined

Antwoord 2, autoriteit 9%

Om de bijgewerkte vraag te beantwoorden — dit kan overdreven zijn, maar het zal de grootte van je klassen afdrukken tijdens het compileren. Er is een ongedocumenteerde opdrachtregelschakelaar in de Visual C++-compiler die de volledige indelingen van klassen weergeeft, inclusief hun grootte:

Die schakeloptie is /d1reportSingleClassLayoutXXX, waarbij XXX substringovereenkomsten uitvoert met de klassenaam.

https: //devblogs.microsoft.com/cppblog/diagnosing-hidden-odr-violations-in-visual-c-and-fixing-lnk2022/


Antwoord 3, autoriteit 4%

BEWERKT (3jun2020)
Deze truc werkt IN ALLE C-COMPILERS. Voor Visual C++:

struct X {
    int a,b;
    int c[10];
};
int _tmain(int argc, _TCHAR* argv[])
{
    int dummy;
    switch (dummy) {
    case sizeof(X):
    case sizeof(X):
        break;
    }
    return 0;
}

—— Build gestart: Project: cpptest, Configuratie: Debug Win32 —— cpptest.cpp c:\work\cpptest\cpptest\cpptest.cpp(29): fout C2196: case value ’48’ al gebruikt ========== Build: 0 geslaagd, 1
mislukt, 0 up-to-date, 0 overgeslagen ==========

Voor andere compilers die alleen “duplicate case value” afdrukken, zie mijn antwoord op deze vraag:
Hoe kan ik het resultaat afdrukken van sizeof() tijdens het compileren in C?


Antwoord 4, autoriteit 3%

Wat is er mis met sizeof? Dit zou moeten werken op objecten en klassen.

void foo( bar* b )
{
  int i = sizeof bar;
  int j = sizeof *b;
  // please remember, that not always i==j !!!
}

Bewerken:

Dit is het voorbeeld waar ik aan dacht, maar om de een of andere reden werkt het niet. Kan iemand me vertellen wat er aan de hand is?

#include <iostream>
using namespace std;
class bar {
public: int i;
        bar( int ii ) { i = ii; }
        virtual ~bar(){ i = 0; }
        virtual void d() = 0;
};
class bar2: public bar {
public: long long j;
        bar2( int ii, long long jj ):bar(ii){ j=jj; }
        ~bar2() { j = 0; }
        virtual void d() { cout <<  "virtual" << endl; };
};
void foo( bar *b )
{
        int i = sizeof (bar);
        int j = sizeof *b;
        cout << "Size of bar = " << i << endl;
        cout << "Size of *b  = " << j << endl;
        b->d();
}
int main( int arcc, char *argv[] )
{
        bar2 *b = new bar2( 100, 200 );
        foo( b );
        delete b;
        return 0;
}

De toepassing is uitgevoerd op linux (gcc 4.4.2):

[[email protected] ~/tmp] ./sizeof_test
Size of bar = 8
Size of *b  = 8
virtual

Antwoord 5, autoriteit 2%

sizeof() bepaalt de grootte tijdens het compileren.

Het werkt pas tijdens het compileren, dus je kunt het niet gebruiken met de preprocessor.


Antwoord 6, autoriteit 2%

Deze macro is gebaseerd op het antwoord van grep. Definieer de macro zoals hieronder:

#define COMPILE_TIME_SIZEOF(t)      template<int s> struct SIZEOF_ ## t ## _IS; \
                                    struct foo { \
                                        int a,b; \
                                    }; \
                                    SIZEOF_ ## t ## _IS<sizeof(t)> SIZEOF_ ## t ## _IS;

Gebruik het dan als volgt:

COMPILE_TIME_SIZEOF(long);

En je krijgt een uitvoer zoals hieronder:

error: 'SIZEOF_long_IS<4> SIZEOF_long_IS' redeclared as different kind of symbol
                                         SIZEOF_ ## t ## _IS<sizeof(t)> SIZEOF_ ## t ## _IS;

Nog een beetje een tijdelijke oplossing, maar makkelijk genoeg om te gebruiken.


Antwoord 7

Compilatiegrootte van als waarschuwing, zodat de compilatie kan doorgaan

Hier is een versie die een waarschuwing geeft in plaats van een fout:

   /** Compile-time sizeof as a warning so
        compilation can continue */
    struct TestStruct
    {
      int i1;
      float f1;
      const char* pchar1;
      double d1;
      char c1;
      void* pv1;
      bool b1;
    };
    template<unsigned int n>
    struct PrintNum {
        enum { value = n };
    };
    template<int number> 
    struct _{ operator char() { return number + 256; } };
    #define PRINT_AS_WARNING(constant) char(_<constant>())    
    int main() 
    {
        PRINT_AS_WARNING(PrintNum<sizeof(TestStruct)>::value);
        return 0;
    }

Zie het draaien op Godbolt. Even terzijde, je kunt de maat (48) daar direct uit de assembly lezen:

leaq    -1(%rbp), %rax
movq    %rax, %rdi
call    _<48>::operator char()
movl    $0, %eax
leave
ret

Antwoord 8

Er is operator sizeof( int ), sizeof( char )dus ik denk dat het mogelijk is en aanroep ziet er waarschijnlijk uit als sizeof( MyClass )


Antwoord 9

Nog een truc die ervoor zorgt dat de VC++2010-compiler klaagt over onjuist gebruik van het compileertijdgetal:

// cpptest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
struct X {
    int a[11];
    char c[2];
};
void proc1(void* s[1]) {
}
int _tmain(int argc, _TCHAR* argv[])
{
    int b[sizeof(X)];
    proc1(b);
    return 0;
}

1>—— Build gestart: Project: cpptest, Configuratie: Release Win32
—— 1> cpptest.cpp 1>cpptest.cpp(14): fout C2664: ‘proc1’: kan parameter 1 niet converteren van ‘int [48]’ naar ‘void *[]’ 1>
Typen waarnaar wordt verwezen, zijn niet gerelateerd; conversie vereist reinterpret_cast,
Cast in C-stijl of cast in functie-stijl
========== Build: 0 geslaagd, 1 mislukt, 0 up-to-date, 0 overgeslagen ==========

Daarom is sizeof (struct X) 48. Dit werkt ook voor C-code.


Antwoord 10

Dit is het fragment dat ik gebruik:

template <typename T>
void get_sizeof() {
    switch (*((int*)0x1234)) { case sizeof(T): case sizeof(T):; }
}

Om de grootte te krijgen, moet u de functie ergens in de code instantiëren, bijvoorbeeld binnen een instructie:

struct S { long long int ill; };
get_sizeof<S>;

De fout ziet er als volgt uit:

error: duplicate case value '8'
switch (*((int*)0x1234)) { case sizeof(T): case sizeof(T):; }
                                                ^

Antwoord 11

Ik heb een tool ontwikkeld, genaamd compile-time printer, om waarden en typen uit te voeren tijdens het compileren.

Je kunt het online proberen onder: https://viatorus.github.io/compile -time-printer/

De repository is hier te vinden: https://github.com/Viatorus/compile- tijdprinter

Om de grootte van een willekeurig type als uitvoer te krijgen:

constexpr auto unused = ctp::print(sizeof(YourType));

Other episodes