2012-07-17 12 views
15

Wykorzystanie pamięci jest dość krytyczne w mojej aplikacji. Dlatego mam konkretne potwierdzenia, które sprawdzają rozmiar pamięci w czasie kompilacji i dają static_assert, jeśli rozmiar jest inny niż wcześniej uważaliśmy za poprawny.Jak połączyć static_assert z sizeof i stringify?

Mam zdefiniowane makra tak:

#define CHECKMEM(mytype, size) static_assert((sizeof(objectType) == size)), "Size incorrect for " #mytype "!"); 

To makro sprawia, że ​​bardzo łatwo pisać to:

CHECKMEM(Book,144); 
CHECKMEM(Library,80); 

Problem polega na tym, że gdy ten static_assert gaśnie, może to być dość trudno dowiedzieć się, jaki powinien być nowy rozmiar (np. używając ukrytej opcji kompilatora "/ d1 reportAllClassLayout"). Byłoby znacznie wygodniej, gdybym mógł uwzględnić rzeczywisty rozmiar, więc zamiast:

Niepoprawny rozmiar dla książki!

Byłoby pokazać

Rozmiar nieprawidłowy dla książki! (Oczekiwano 144, rozmiar to 152)

Próbowałem pisać coś takiego:

#define CHECKMEM(mytype, size) static_assert((sizeof(objectType) == size)), "Size incorrect for " #mytype "! (expected" #size ", size is " #sizeof(mytype) ")"); 

Ale nie można używać operatora (#) stringize na wywołaniu funkcji.

Próbowałem też dodanie trick dwukrotnie stringize, tak:

#define STR1(x) #x 
#define STR2(x) STR1(x) 
#define CHECKMEM(mytype, size) static_assert((sizeof(objectType) == size)), "Size incorrect for " #mytype "! (expected" #size ", size is " STR2(sizeof(mytype)) ")"); 

Ale zamiast drukować size is 152 drukuje size is sizeof(Book).

Czy istnieje sposób na łańcuchowanie wyniku sizeof w static_assert?

+2

Zauważ, że 'sizeof' to * nie * wywołanie funkcji –

+2

Problem polega na tym, że drugi argument polecenia' static_assert' musi być literałem łańcuchowym i nie możesz go zbudować w preprocesorze, ponieważ nie możesz użyć sizeof tam . – pmr

Odpowiedz

17

użyję wysyłki na szablonie funkcji, aby wykonać sprawdzenie:

#include <cstddef> 

template <typename ToCheck, std::size_t ExpectedSize, std::size_t RealSize = sizeof(ToCheck)> 
void check_size() { 
    static_assert(ExpectedSize == RealSize, "Size is off!"); 
} 

struct foo 
{ 
    char bla[16]; 
}; 

int main() 
{ 
    check_size<foo, 8>(); 
    return 0; 
} 

Wyniki w:

informacje
In instantiation of ‘void check_size() [with ToCheck = foo; long unsigned int ExpectedSize = 8ul; long unsigned int RealSize = 16ul]’: 
bla.cpp:15:22: required from here 
bla.cpp:5:1: error: static assertion failed: Size is off! 

debugowanie jest w parametrach szablonów z back-śladu.

Jeśli jest to naprawdę lepsze, musisz zdecydować, a także zależy to od kompilatora. Pozwala także ukryć spodziewany rozmiar za pomocą mapy szablonów, aby podsumować maksymalny rozmiar i inne fantazyjne rzeczy.

3

zależności od kompilatora, szablony mogą być w stanie pomóc:

template<int s, int t> struct check_size { 
    static_assert(s == t, "wrong size"); 
}; 
check_size<2+2, 5> doubleplusungood; 

gcc wyjścia:

prog.cpp: In instantiation of 'check_size<4, 5>': 
prog.cpp:5:20: instantiated from here 
prog.cpp:2:3: error: static assertion failed: "wrong size" 
1

Jak odkryto, problemem jest tutaj (patrz również ten very similar question):

#define CHECKMEM(mytype, size) #sizeof(mytype) 

Nie można tego zrobić, ponieważ strufikacja jest wykonywana przez prep rocessor, a sizeof jest oceniany podczas kompilacji.

Powiązane problemy