2015-08-14 6 views
9

Gibt es einen Weg (Merkmal oder so) zu erkennen, ob struct/class etwas Padding hat?Erkennen, ob die Struktur padding hat

Ich brauche keine plattformübergreifende oder standardisierte Lösung, ich brauche es für MSVC2013.

Ich kann es überprüfen, wie

namespace A 
{ 
    struct Foo 
    { 
     int a; 
     bool b; 
    }; 
} 

#pragma pack(push, 1) 
namespace B 
{ 
    struct Foo 
    { 
     int a; 
     bool b; 
    }; 
} 
#pragma pack(pop) 

static const bool has_padding = sizeof(A::Foo) != sizeof(B::Foo); 

Aber C++ erlaubt es nicht (soweit ich weiß) erzeugen diese nicht-invasive (ohne bestehende Strukturen zu berühren)

Im Idealfall würde Ich mag bekommen Arbeit so etwas wie dieses

template <typename T> 
struct has_padding_impl 
{ 
    typedef __declspec(align(1)) struct T AllignedT; 
}; 

template <typename T> 
struct has_padding : typename std::conditional<sizeof(typename has_padding_impl<T>::AllignedT) == sizeof(T), 
               std::false_type, 
               std::true_type>::type{}; 

EDIT - Warum das ich benötige?

Ich bin mit vorhandenen Serialisierung System arbeiten, die nur einige struct speichern void* ihnen (innen generische Funktion) und speichern sizeof(T) Anzahl von Bytes ... Solche Binärdatei nehmen ist nicht tragbar auf Plattformen wir zielen, da Verschiedene Compiler werden verwendet, daher gibt es keine Garantie, wie das Padding eingefügt wird. Wenn ich alle T statisch erkennen könnte, die Strukturen mit Auffüllung sind, kann ich den Benutzer zwingen, Padding manuell einzufügen (einige Steuerauffüllung, nicht nur zufälliger Müll), so dass es kein "zufälliges" Auffüllen gibt. Ein weiterer Vorteil ist, wenn ich zwei Dateien von demselben Szenario vergleiche, werden sie gleich aussehen.

bearbeiten 2 je mehr ich darüber nachdenke, erkennen, je mehr ich mich Cross-Plattform-Lösung benötigen. Wir entwickeln hauptsächlich auf msvc2013, aber unsere Anwendung wird in msvc2012 und clang erstellt. Aber wenn ich alle compiler-generierten Auffüllen in msvc2013 entdeckt und loswird, gibt es keine Garantie, dass andere Compiler keine Auffüllung einfügen ... (so msvc2013 Erkennung ist nicht genug)

+4

Warum denken Sie, dass Sie das brauchen? –

+1

Padding verhält sich ähnlich wie ein unbenanntes Mitglied. Da Sie keine Mitglieder aufzählen können, ist es unmöglich, zwischen normalen Mitgliedern und solchen "unbenannten Mitgliedern" zu unterscheiden, die als Auffüllen dienen. – MSalters

+0

Sie wissen, dass Sie mit der Option "Struct Member Alignment" auf der Codegenerierungs-Konfigurationsseite das MSVC-Auffüllverhalten angeben können, richtig? –

Antwort

-1

Vielleicht sollten Sie etwas wie versuchen dies:

#include <iostream> 
using namespace std; 

struct A 
{ 
    int a; 
    bool b; 
}; 

int main(int argc, char *argv[]) 

{ 
    A foo; 

    cout << "sizeof struct = " << sizeof(A) << endl; 
    cout << "sizeof items = " << sizeof(foo.a) + sizeof(foo.b) << endl; 
    return 0; 
} 

ich habe:

sizeof struct = 8 
sizeof items = 5 

ich bin auf Ubuntu 14.04.

+1

Dies berücksichtigt nicht zusätzlichen Speicherbereich, der nicht aufgefüllt wird (wie ein vPtr), und erfordert die manuelle Aufzählung der Elemente. – Quentin

+0

Vielen Dank, leider brauche ich generische Lösung, es ist nicht möglich, alle Strukturelemente aller Struktur per Hand zu nummerieren – relaxxx

2

Benötigen Sie diese Informationen während der Laufzeit? Weil, wenn Sie es in Bauzeit wissen wollen, ich glaube, dass Sie static_assert verwenden können, um diese Information zu erhalten.

struct foo 
{ 
    uint64_t x; 
    uint8_t y; 
}; 
#define EXPECTED_FOO_SIZE (sizeof(uint64_t) + sizeof(uint8_t)) 
static_assert(sizeof(foo) == EXPECTED_FOO_SIZE, "Using padding!"); 

Wenn Sie es während der Laufzeit benötigen, können Sie so etwas wie versuchen:

static const bool has_padding = (sizeof(foo) == EXPECTED_FOO_SIZE); 

Überprüfen Sie auch diese link aus früheren Post, vielleicht wird es helfen.

+2

Vielen Dank, leider brauche ich generische Lösung, es ist nicht möglich, alle Strukturelemente aller Struktur von Hand – relaxxx

0

dieses Makro ausprobieren:

#define TO_STR(str) #str 
#define DECL_STRUCT_TEST_ALIGNED(structName, test_alignment, body) \ 
_Pragma(TO_STR(pack(push,test_alignment)))\ 
struct test_##structName \ 
body ; \ 
_Pragma(TO_STR(pack(pop))) \ 
struct structName \ 
body; \ 
static const bool has_padding_##structName = sizeof(test_##structName)!=sizeof(structName); 

DECL_STRUCT_TEST_ALIGNED(bar, 1, 
{ 
         int a; 
         bool b; 
        } 
        ) 


DECL_STRUCT_TEST_ALIGNED(foo,1, 
{ 
         int a; 
         int b; 
        }) 

Und nun zur Laufzeit können Sie testen:

if (has_padding_foo) 
{ 
    printf("foo has padding\n"); 
} else { 
    printf("foo doesn't have padding\n"); 
} 
if (has_padding_bar) 
{ 
    printf("bar has padding\n"); 
} else { 
    printf("bar has no padding\n"); 
} 

Und OFC, können Sie static_assert verwenden, wenn Sie Fehler bei der Kompilierung erhalten möchten.

+0

Thank Sie, aber ich sehe nicht, wie das funktioniert, ohne bestehende Struktur zu berühren, ich brauche 'Merkmal'. Bitte, sehen Sie sich meine Frage – relaxxx

+0

gut an, Sie müssen den Inhalt nicht ändern, Sie müssen das Paket nicht ändern, Sie müssen es jedoch mit dem obigen Makro deklarieren. Die Struktur wird nicht berührt. – MichaelCMS

+0

Durch nicht berühren, meinen Sie, Sie können die Datei nicht ändern, wo die Struktur deklariert ist? – MichaelCMS