Ответ 1
Формально struct
может иметь дополнение, чтобы его размер был больше 1.
I.e., формально вы не можете reinterpret_cast
и иметь полностью переносимый код, за исключением массива ¹an только одного элемента.
Но для практики, несколько лет назад кто-то спросил, есть ли теперь какой-нибудь компилятор, который по умолчанию дал бы sizeof(T) > 1
для struct T{ char x; };
. Я еще не видел ни одного примера. Поэтому на практике можно просто static_assert
, чтобы размер был равен 1, и не волнуйтесь, что этот static_assert
не будет работать в какой-либо системе.
т.е.
S const a1[] = { {'a'}, {'4'}, {'2'}, {'\0'} };
static_assert( sizeof( S ) == 1, "!" );
char const* const a2 = reinterpret_cast<char const*>( a1 );
for( int i = 0; i < 4; ++i )
{
assert( a1[i].v == a2[i] );
}
Так как возможно интерпретировать С++ 14 и более поздние стандарты таким образом, что индексирование имеет Undefined Behavior, основанный на своеобразной интерпретации "массива" как относящийся к некоторому исходному массиву, можно вместо этого написать этот код в более неудобном и подробном, но гарантированном действительном способе:
// I do not recommend this, but it one way to avoid problems with some compiler that's
// based on an unreasonable, impractical interpretation of the C++14 standard.
#include <assert.h>
#include <new>
auto main() -> int
{
struct S
{
char v;
};
int const compiler_specific_overhead = 0; // Redefine per compiler.
// With value 0 for the overhead the internal workings here, what happens
// in the machine code, is the same as /without/ this verbose work-around
// for one impractical interpretation of the standard.
int const n = 4;
static_assert( sizeof( S ) == 1, "!" );
char storage[n + compiler_specific_overhead];
S* const a1 = ::new( storage ) S[n];
assert( (void*)a1 == storage + compiler_specific_overhead );
for( int i = 0; i < n; ++i ) { a1[i].v = "a42"[i]; } // Whatever
// Here a2 points to items of the original `char` array, hence no indexing
// UB even with impractical interpretation of the C++14 standard.
// Note that the indexing-UB-free code from this point, is exactly the same
// source code as the first code example that some claim has indexing UB.
char const* const a2 = reinterpret_cast<char const*>( a1 );
for( int i = 0; i < n; ++i )
{
assert( a1[i].v == a2[i] );
}
}
Примечания:
¹ Стандарт гарантирует отсутствие прокладки в начале struct
.