2015-08-14 3 views
9

Есть ли способ (признак или так) обнаружить, если у структуры/класса есть отступы?Обнаружить, если у структуры есть отступы

Мне не нужны кросс-платформенные или стандартизованные решения, мне это нужно для MSVC2013.

я могу проверить это, как

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

Но C++ не позволяет (насколько я знаю) порождают это неинвазивный (не касаясь существующих структур)

В идеале я хотел бы получить работает что-то вроде этого

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 - Зачем мне это нужно?

I'am работает с существующей системой сериализации, хранящей некоторой просто-структуру, принимая void* к ним (внутри родовой функции) и хранить sizeof(T) числом байт, ... Такой бинарный файл не является переносимым на платформах мы ориентируемся, так как используются разные компиляторы, поэтому нет никакой гарантии, как добавляется прокладка. Если бы я мог статически обнаруживать все T, которые являются структурами с заполнением, я могу заставить пользователя вручную вставлять дополнения (некоторые элементы управления, например, не просто случайный мусор), поэтому нет «случайного» заполнения. Другое приключение - когда я разберу два файла с сохранением одного и того же scenerio, они будут выглядеть одинаково.

Редактировать 2 Чем больше я думаю об этом, тем больше я понимаю, что мне нужно кросс-платформенное решение. В основном мы разрабатываем на msvc2013, но наше приложение находится в окончательной версии в msvc2012 и clang. Но если я обнаружил и избавился от всех дополнений, созданных с помощью компилятора, в msvc2013, нет гарантии, что другой компилятор не вставляет прокладку ... (поэтому обнаружение msvc2013 недостаточно)

+4

Почему, по-вашему, вам это нужно? –

+1

Padding ведет себя как неназванный участник. Поскольку вы не можете перечислять членов, невозможно отличить нормальных членов и тех «неназванных членов», которые выступают в качестве дополнения. – MSalters

+0

Вы знаете, что вы можете указать поведение дополнений MSVC, используя параметр «Выравнивание элементов Struct» на странице конфигурации Code Generation, верно? –

ответ

-1

Может быть, вам стоит попробовать что-то вроде это:

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

я получил:

sizeof struct = 8 
sizeof items = 5 

Я на Ubuntu 14.04.

+1

Это не учитывает дополнительное пространство, которое не заполняется (например, vPtr), и требует перечисления элементов вручную. – Quentin

+0

Спасибо, к сожалению, мне нужно общее решение, невозможно перечислять все элементы структуры всей структуры вручную – relaxxx

2

Нужна ли вам эта информация во время выполнения? Потому что, если вы хотите узнать это во время сборки, я считаю, что вы можете использовать static_assert, чтобы получить эту информацию.

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

Если вам это нужно во время выполнения, вы можете попробовать что-то вроде:

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

Также проверьте эту link от предыдущей публикации, может быть, это поможет.

+2

Спасибо, к сожалению, мне нужно общее решение, невозможно перечислить все элементы структуры всей структуры вручную – relaxxx

0

Попробуйте этот макрос:

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

И теперь, во время выполнения теста вы можете:

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

И OFC, вы можете использовать static_assert, если вы хотите, чтобы получить ошибку во время компиляции.

+0

Thank вы, но я не вижу, как это будет работать, не касаясь существующей структуры, мне нужно «черта». Пожалуйста, см. Мой вопрос – relaxxx

+0

, вам не нужно изменять его содержимое, вам не нужно менять его пакет, однако вам нужно объявить его, используя указанный выше макрос. Структура не тронута. – MichaelCMS

+0

Не трогая, вы имеете в виду, что вы не можете изменить файл, в котором объявлена ​​структура? – MichaelCMS