2015-06-26 7 views
8

Можно ли сделать двойной массив структурой, состоящей из двухместных?Листинг двойного массива для структуры удвоений

struct A 
{ 
    double x; 
    double y; 
    double z; 
}; 

int main (int argc , char ** argv) 
{ 
    double arr[3] = {1.0,2.0,3.0}; 
    A* a = static_cast<A*>(static_cast<void*>(arr)); 
    std::cout << a->x << " " << a->y << " " << a->z << "\n"; 
} 

Отпечатано 1 2 3. Но гарантированно ли он работать каждый раз с любым компилятором?

EDIT: В соответствии с

9.2.21: указатель на объект структуры стандартной компоновки, соответствующим образом преобразованы? используя reinterpret_cast, указывает на его начальный член (...) и наоборот.

, если я заменю мой код с

struct A 
{ 
    double & x() { return data[0]; } 
    double & y() { return data[1]; } 
    double & z() { return data[2]; } 
private: 
    double data[3]; 
}; 

int main (int, char **) 
{ 
    double arr[3] = {1.0,2.0,3.0}; 
    A* a = reinterpret_cast<A*>(arr); 
    std::cout << a->x() << " " << a->y() << " " << a->z() << "\n"; 
} 

тогда гарантированно работать. Верный? Я понимаю, что многие люди не считают эту эстетику приятной, но есть преимущества в работе со структурой и не нужно копировать данные входных массивов. Я могу определить функции-члены в этой структуре для вычисления скалярных и векторных продуктов, расстояний и т. Д., Что сделает мой код намного понятнее, чем если бы я работал с массивами.

Как насчет

int main (int, char **) 
{ 
    double arr[6] = {1.0,2.0,3.0,4.0,5.0,6.0}; 
    A* a = reinterpret_cast<A*>(arr); 
    std::cout << a[0].x() << " " << a[0].y() << " " << a[0].z() << "\n"; 
    std::cout << a[1].x() << " " << a[1].y() << " " << a[1].z() << "\n"; 
} 

Это также гарантирует работу или компилятор может поставить что-то после того, как члены данных так, что sizeof(A) > 3*sizeof(double)? И есть ли какой-либо переносной способ предотвратить компилятор?

+0

Любой может написать компилятор, так что это сложный вопрос. Почему бы не указать компиляторы, которые вы собираетесь использовать? Я предполагаю, что все основные компиляторы справляются с этим одинаково, и это действительно работает. –

+0

Скорее всего, нет (в случае, если вы хотите использовать не только двойной там), из-за [выравнивания структуры данных] (https://en.wikipedia.org/wiki/Data_structure_alignment) –

+0

Вы нарушаете строгое правило сглаживания. – Jarod42

ответ

8

Нет, это не гарантировано.

Единственное, запрещающее любой компилятор вставлять отступы между x и y, или между y и z здравый смысл. В любом языковом стандарте нет правил, которые бы запретили его.

Даже если нет прокладки, даже если представление A точно такое же, как и у double[3], то оно по-прежнему недействительно. Язык не позволяет вам притворяться, что один тип действительно другой тип. Вам даже не разрешено рассматривать экземпляр struct A { int i; };, как будто это struct B { int i; };.

1

Из всего, что я знаю, ответ: да.

Единственная вещь, которая может вас отбросить, - это директива #pragma с очень необычным параметром выравнивания для структуры. Если, например, double набирает 8 байтов на вашем компьютере, а директива #pragma указывает, чтобы выровнять каждый элемент по 16-байтовым границам, что может вызвать проблемы. Кроме этого вы в порядке.

1

Нет, это не гарантируется, даже если он должен работать со всеми компиляторами я знаю по общей архитектуре, поскольку спецификация языка C говорит:

6.2.6 Представления типов 6.2.6.1 Общие сведения1 представлений всех типы не указаны, кроме как указано в этом подпункте. И ничего не говорит о заполнении по умолчанию в структуре.

Конечно, общие архитектуры используют не более 64 бит, размер которых равен удвоенной по этой архитектуре, поэтому не должно быть дополнений, и ваше преобразование должно работать.

Но остерегайтесь: вы явно вызывая Неопределенное поведение, и следующее поколение компиляторов могли бы сделать что-нибудь при составлении такого броска.

-2

Я не согласен с консенсусом здесь. Структура с тремя двойниками в нем, точно такая же, как массив с 3 двойниками в нем. Если вы специально не структурируете структуру по-разному и находитесь на странном процессоре с нечетным количеством байтов для парных разрядов.

Это не встроенный в язык, но я бы чувствовал себя в безопасности в этом. Стиль мудрый я бы не сделал, потому что это просто сбивает с толку.

2

Стандарт дает небольшие гарантии относительно макета памяти объектов.

Для классов/структур:

9.2./15: Нестатических элементы данных одного класса с тем же контролем доступа распределяется таким образом, чтобы последующие элементы имеют старшие адреса в пределах объекта класса. Порядок распределения нестатических данных членов с различным контролем доступа не указан. Реализация требования к выравниванию могут привести к тому, что два соседних элемента не будут распределены сразу друг за другом; поэтому могут потребоваться области для управления виртуальными функциями и виртуальными базовыми классами.

Для массивов элементы смежные. Ничего не сказано о выравнивании, так что он может или не может использовать те же самые правила выравнивания, чем в структуры:

8.3.4: Объект типа массива содержит смежно выделенную непустое множество N подобъектах типа Т.

Единственное, что вы можете быть уверены в вашем конкретном примере, что a.x соответствует arr[0], при использовании reinterpret_cast:

9.2.21: Указатель на объект структуры стандартного макета, соответствующим образом преобразованный с использованием reinterpret_cast, указывает на его начальный член (...) и наоборот. [
>

 Смежные вопросы

  • Нет связанных вопросов^_^