2015-08-14 23 views
9

C'è un modo (tratto o così) da rilevare, se struct/class ha qualche padding?Rileva se struct ha padding

Non ho bisogno di una soluzione multipiattaforma o standardizzata, ne ho bisogno per MSVC2013.

posso controllare come

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); 

Ma C++ non permette (per quanto ne so) generare questo non invasivo (senza toccare le strutture esistenti)

Idealmente mi piacerebbe ottenere qualcosa di lavorare in questo modo

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 - Perché ho bisogno di questo?

I'am lavorando con sistema esistente serializzazione, che immagazzinano alcuni struct solo prendendo void* a loro (all'interno funzione generica) e memorizzare sizeof(T) numero di byte ... Tale file binario non è portabile su piattaforme sulle quali puntiamo, dal momento che vengono utilizzati diversi compilatori, quindi non vi è alcuna garanzia su come viene inserito il padding. Se potessi rilevare staticamente tutte le T che sono strutture con padding, posso forzare l'utente a inserire manualmente il padding (un po 'di controllo padding, ad esempio non solo una spazzatura casuale), quindi non c'è padding "casuale". Un altro inconveniente è che, quando differisco due file di salvataggio dello stesso scenerio, avranno lo stesso aspetto.

modifica 2 più ci penso, più mi rendo conto di aver bisogno di una soluzione multipiattaforma. Sviluppiamo principalmente su msvc2013 ma la nostra applicazione è in fase di costruzione finale in msvc2012 e clang. Ma se ho rilevato e rimosso tutti i padding generati dal compilatore in msvc2013, non c'è alcuna garanzia che l'altro compilatore non inserisca padding ... (quindi il rilevamento msvc2013 non è sufficiente)

+4

Perché pensi di aver bisogno di questo? –

+1

Il riempimento si comporta come un membro senza nome. Poiché non puoi enumerare membri, è impossibile distinguere tra membri normali e quei "membri senza nome" che fungono da padding. – MSalters

+0

Sapete che è possibile specificare il comportamento del riempimento MSVC utilizzando l'opzione "Allineamento membri di Struct" nella pagina di configurazione Generazione codice, giusto? –

risposta

-1

Potrebbe essere necessario provare qualcosa di simile questo:

#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; 
} 

ho ottenuto:

sizeof struct = 8 
sizeof items = 5 

sono su Ubuntu 14.04.

+1

Questo non tiene conto dello spazio extra che non è padding (come un vPtr) e richiede enumerazione manuale dei membri. – Quentin

+0

Grazie, purtroppo, ho bisogno di una soluzione generica, non è possibile enumerare tutti i membri struct di tutte le struct a mano – relaxxx

2

Avete bisogno di queste informazioni durante il tempo di esecuzione? Perché se vuoi saperlo in tempo di costruzione, credo che tu possa usare static_assert per ottenere queste informazioni.

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!"); 

Se ne avete bisogno durante la fase di esecuzione, si può provare qualcosa di simile:

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

Controllare anche questo link da post precedente, forse aiuterà.

+2

Grazie, purtroppo ho bisogno di una soluzione generica, non è possibile enumerare tutti i membri struct di tutte le struct a mano – relaxxx

0

provare questa macro:

#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; 
        }) 

E ora, in fase di esecuzione è possibile verificare:

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"); 
} 

E OFC, è possibile utilizzare static_assert se si vuole ottenere l'errore in fase di compilazione.

+0

Grazie tu, ma non vedo come funzionerà senza toccare la struttura esistente, ho bisogno di 'tratto '. Per favore, vedi la mia domanda – relaxxx

+0

beh, non è necessario modificarne il contenuto, non è necessario cambiarlo, è comunque necessario dichiararlo usando la macro sopra. La struttura non viene toccata. – MichaelCMS

+0

Per non toccare, vuoi dire che non puoi modificare il file in cui è dichiarata la struttura? – MichaelCMS