2016-10-07 4 views
-1

Недавно я опубликовал вопрос о unaligned memory access, но, учитывая ответ, я немного потерялся. Я часто слышу, что «доступ к выровненной памяти намного эффективнее, чем непривязанный доступ», но я на самом деле не уверен, что такое неизмененная память. Следовательно:Объявление, управление и доступ к нераспределенной памяти в C++

  • Что такое неизмененная память?
  • Как вы объявляете что-то неглавное в C++? (небольшая примерная программа)
  • Как вы получаете доступ и манипулируете чем-то несимметричным в C++? (небольшая примерная программа)
  • Есть ли способ манипулировать неизмененной памятью с помощью определенного подхода к поведению или все это зависит от платформы/неопределенного поведения на C++?
+3

Из ответа, на который вы ссылаетесь: «на C++ невозможно написать код, который будет выполнять неприсоединенный доступ, не вызывая неопределенного поведения». – molbdnilo

ответ

3

Является ли что-то несогласованным или нет, зависит от типа данных и его размера. Как объясняет Грегг.

Хорошо написанная программа, как правило, не имеет равномерного доступа к памяти, за исключением случаев, когда компилятор представляет ее. (Да, это происходит во время векторизации, но давайте пропустим это).

Но вы можете написать программу на C++, чтобы принудительно использовать неравномерный доступ к памяти. Код ниже делает именно это.

#include <iostream> 
using namespace std; 
int main() { 

    int a[3] {1, 2, 3}; 

    cout << *((long long *)(&a[0])) << endl; 
    cout << *((long long *)(&a[1])) << endl; 

    cout << (long long) (&a[0]) << endl; 
    cout << (long long) (&a[1]) << endl; 

    return 0; 

} 

Выход кода это

8589934593 
12884901890 
70367819479584 
70367819479588 

Что делает эта программа? Я объявляю целочисленный массив размера 3. Этот массив будет выровнен по 4 байт, потому что int - это 4-байтовый тип данных (по крайней мере, на моей платформе). Таким образом, адрес [0] делится на 4. Теперь адрес обоих [0] и [1] делится на 4, но только адрес одного из них делится на 8.

Так что если я введите адрес [0] и [1] в указатель на длинный (который является 8-байтным типом данных на моей платформе), а затем почуйте эти два указателя, один из них будет негласным доступом к памяти. Это не неопределенное поведение AFAIK, но оно будет медленнее, чем выровненный доступ к памяти.

Как вы видите, этот код содержит стили стиля C, что не является хорошей практикой. Но я думаю, что для обеспечения какого-то странного поведения это нормально.

дайте мне знать, если у вас есть вопрос о выходе кода. Вы должны знать о конкретизации и представлении целых чисел для понимания первых двух строк. Третья и четвертая строки являются адресами первых двух элементов целочисленного массива. Это должно быть легче понять.

+0

Оказалось, что нарушение строгой псевдонимы - неопределенное поведение на C++. Та часть, которую я не знал. – esam

0

принимая пример 32 разрядного компьютера, чтение 4 байтовое слово данных:

В аппаратных средствах, 32-битный компьютер считывает 4 байта в то время, но только на каждом 4 байта. Это связано с тем, что шина памяти имеет ширину 4 байта.

Если ваши 4 байтовые данные не запускаются на одной из этих четырехбайтовых границ, компьютер должен дважды считывать память, а затем объединять 4 байта с одним регистром.

Основываясь на выбранной архитектуре, компилятор знает об этом и размещает/разбивает структуры данных так, что два байтовых данных встречаются на двух байтовых границах, 4 байтовых данных начинаются с 4 байтовых границ и т. Д. Это специально, чтобы избежать ошибочного выравнивания читает.

Вы можете получить неверные чтения, если вы читаете данные в виде байтов (например, из последовательного протокола), а затем получаете к ним 32-разрядные слова. Избегайте этого в критическом критически важном коде. Обычно он заботится о вас и не является проблемой.