Declare, manipulate and access unaligned memory in C++ [closed]
Asked Answered
C

2

2

I recently posted a question about unaligned memory access, but given the answer, I am a little lost. I often hear that "aligned memory access is far more efficient than unaligned access", but I am actually not sure what is unaligned memory. Consequently:

  • What is unaligned memory?
  • How you declare something unaligned in C++? (small example program)
  • How do you access and manipulate something unaligned in C++? (small example program)
  • Is there is a way to manipulate unaligned memory in with a defined behavior approach or all of that is platform dependent/undefined behavior in C++?
Chrisoula answered 7/10, 2016 at 17:0 Comment(1)
From the answer you linked to: "in C++ it's not possible to write code that would perform an unaligned access without causing undefined behaviour".Brachium
T
5

Whether something is unaligned or not depends on the data type and its size As the answer from Gregg explains.

A well-written program usually does not have unaligned memory access, except when the compiler introduces it. (Yes, that happens during vectorization but let's skip that).

But you can write program in C++ to force unaligned memory access. The code below does just that.

#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;

}

The output of the code is this

8589934593
12884901890
70367819479584
70367819479588

What this program does? I declare an integer array of size 3. This array will be 4 byte aligned because int is a 4 byte data type (at least on my platform). So the address of a[0] is divisible by 4. Now address of both of a[0] and a[1] is divisible by 4 but only address of one of them is divisible by 8.

So if I cast the address of a[0] and a[1] to a pointer to long long (which is an 8 byte data type on my platform) and then deference these two pointers, one of them will be an unaligned memory access. This is not undefined behavior AFAIK, but it is going to be slower than aligned memory access.

As you see this code contains C style casts which is not a good practice. But I think for enforcing some strange behavior that is fine.

let me know if you have question about the output of the code. You should know about endianness and representation of integers to understand the first two lines. The third and fourth line are address of the first two elements of the integer array. That should be easier to understand.

Tortosa answered 7/10, 2016 at 22:4 Comment(1)
It turned out breaking strict aliasing is undefined behavior in C++. That part I didn't know.Tortosa
O
0

taking an example of a 32 bit computer reading a 4 byte word of data:

In the hardware, a 32 bit computer reads 4 bytes at a time but only on every 4th byte. This is because the memory bus is 4 bytes wide.

If your 4 byte data does not start on one of those 4 byte boundaries, the computer must read the memory twice, and then assemble the 4 bytes to a single register internally.

Based on the architecture chosen, the compiler knows this and places/pads data structures so that two byte data occur on two byte boundaries, 4 byte data starts on 4 byte boundaries, etc. This is specifically to avoid mis-aligned reads.

You can get misaligned reads if you read data in as bytes (like from a serial protocol) and then access them as 32 bit words. Avoid this in speed critical code. Usually it is taken care of for you and is not a problem.

Opsonize answered 7/10, 2016 at 21:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.