2014-09-15 2 views
1

Я получаю предупреждение «увеличение литья требует выравнивания целевого типа» при компиляции следующего кода для ARM.изменение требования к выравниванию при литье

char data[2] = "aa"; 
int *ptr = (int *)(data); 

Я понимаю, что требование выравнивания для символа равно 1 байту, а значение int - 4 байта и, следовательно, предупреждение.

Я попытался изменить выравнивание символа с помощью выровненного атрибута.

char data[2] __attribute__((aligned (4))); 
memcpy(data, "aa", 2); 

int *ptr = (int *)(data); 

Но предупреждение не исчезает.

Мои вопросы

  1. Почему не предупреждение уйти?

  2. Поскольку ARM генерирует аппаратное исключение для неправильных доступов, я хочу убедиться, что проблемы выравнивания не возникают. Есть ли другой способ написать этот код, чтобы проблема выравнивания не возникла?

Кстати, при печати alignof (данные), он печатает 4, что означает, выравнивание данных изменяется.

Я использую gcc версию 4.4.1. Возможно ли, что gcc выдаст предупреждение, даже если выравнивание было изменено с помощью атрибута aligned?

+0

Помните, что на большинстве платформ 'int' 32 бита , четыре байта. Ваша строка - всего два байта (три - это строковый ограничитель). –

+0

@JoachimPileborg - Да, поэтому я хочу избавиться от этого предупреждения. Если строка начинается с нечетной границы, это может привести к исключению без выравнивания. – linuxfreak

+0

Возможный дубликат [ARM unaligned доступ к памяти обходной путь] (http://stackoverflow.com/questions/5119496/arm-unaligned-memory-access-workaround) –

ответ

4

Я не совсем понимаю, почему вы хотели бы это сделать ... но проблема в том, что строковый литерал «aa» не сохраняется по выровненному адресу. Компилятор, вероятно, полностью оптимизировал переменную data и поэтому видит код только как int* ptr = (int*)"aa";, а затем дает предупреждение о несоосности. Никакая ошибка в игре с переменной data не изменит, как выравнивается буква «аа».

Чтобы избежать распространения литерала по неверному адресу, вам нужно будет настроить, как строковые литералы хранятся в настройках компилятора, что, вероятно, не очень хорошая идея.

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

Так что ваш код - это чушь. Если вы до сих пор по неизвестным причинам настаивают иметь в ИНТ указатель на строку буквального, я бы какую-то работу вокруг, например, как это:

typedef union 
{ 
    char arr[3]; 
    int dummy; 
} data_t; 

const data_t my_literal = { .arr="aa" }; 
const int* strange_pointer = (const int*)&my_literal; 
+0

Хорошо. Я не имею в виду доступ к строковому литералу с помощью указателя int. Я просто хочу, чтобы иметь возможность указывать указатели из одного типа в другой, не допуская ошибок выравнивания. Допустим, я использую memcpy. Теперь, когда компилятор видит выровненный (4), он выравнивает данные на границе 4 байта, правильно? Но почему я получаю предупреждение? – linuxfreak

+0

@linuxfreak Вы не получили бы аппаратную ошибку, если бы не попытались получить доступ к этой памяти. В процессоре и в компиляторе отсутствует какая-либо форма интеллекта, которая анализирует содержимое самого указателя. Выравнивание '__attribute__' просто выравнивает самую переменную, поэтому в вашем случае это гарантирует, что _pointer_ хранится по выровненному адресу, а не по данным, на которые он указывает. Что касается того, что вы думаете 'char uninit_ptr; memcpy (uninit_ptr, ... 'будет делать, я понятия не имею, что это сбой и запись в большинстве систем, и это не связано с выравниванием. – Lundin

+0

Теперь я изменил char * на char array. Теперь компилятор должен выровнять данные на границе 4 байта и, следовательно, не должно быть предупреждения при передаче его в int *. Но все же я получаю предупреждение. – linuxfreak

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