I'm working on some application that requires big chunk of memory. To decrease memory usage I've switched alignment for huge structure to 1 byte (#pragma pack(1)). After this my struct size was around 10-15% smaller but some problem appeared. When I try to use one of fields of my structure through pointer or reference application just crashes. If I change field directly it work ok.

In test application I found out that problem start to appear after using smaller then 4 bytes field in struct.

Test code:

#pragma pack(1)
struct TestStruct
{
    struct
    {
        long long lLongLong;
        long lLong;
        //bool lBool; // << if uncommented than crash
        //short lShort; // << if uncommented than crash
        //char lChar; // << if uncommented than crash
        //unsigned char lUChar; // << if uncommented than crash
        //byte lByte; // << if uncommented than crash

        __int64 lInt64;
        unsigned int Int;
        unsigned int Int2;
    } General;
};

struct TestStruct1
{
    TestStruct lT[5];
};
#pragma pack()

void TestFunct(unsigned int &pNewLength)
{
    std::cout << pNewLength << std::endl;   
    std::cout << "pNL pointer: " << &pNewLength << std::endl;   
    pNewLength = 7; // << crash

    char *lPointer = (char *)&pNewLength;
    *lPointer = 0x32; // << or crash here
}

int _tmain(int argc, _TCHAR* argv[])
{
    std::cout << sizeof(TestStruct1) << std::endl;

    TestStruct1 *lTest = new TestStruct1();
    TestFunct(lTest->lT[4].General.Int);
    std::cout << lTest->lT[4].General.Int << std::endl;

    char lChar;
    std::cin >> lChar;

    return 0;
}

Compiling this code on ARM (WinCE 6.0) result in crash. Same code on Windows x86 work ok. Changing pack(1) to pack(4) or just pack() resolve this problem but structure is larger.

Why this alignment causes problem ?

有帮助吗?

解决方案 3

On x86, unaligned access is slow. ARM flat out can't do it. Your small types break the alignment of the next element.

Not that it matters. The overhead is unlikely to be more than 3 bytes, if you sort your members by size.

其他提示

You can fix it (to run on WCE with ARM) by using __unaligned keyword, I was able to compile this code with VS2005 and successfully run on WM5 device, by changing:

void TestFunct(unsigned int &pNewLength)

to

void TestFunct(unsigned int __unaligned &pNewLength)

using this keyword will more than double instructions count but will allow to use any legacy structures.

more on this here:

http://msdn.microsoft.com/en-us/library/aa448596.aspx

ARM architectures only support aligned memory accesses. This means four-Byte types can only be read and written at addresses that are a multiple of 4. For two-Byte types, the address must be a multiple of two. Any attempt at unaligned memory access will normally reward you with a DATATYPE_MISALIGNMENT exception and a subsequent crash.

Now you might wonder why you only started seeing crashes when passing your unaligned structure members around as pointers and references; this has to do with the compiler. As long as you directly access the fields in the structure, it knows that you are accessing unaligned data and deals with it by transparently reading and writing the data in several aligned chunks that are split and reassembled. I have seen eVC++ do this to write a four-Byte structure member that was two-Byte-aligned: the generated assembly instructions split the integer into separate, two-Bytes pieces and writes them separately.

The compiler does not know whether a pointer or reference is aligned or not, so as soon as you pass unaligned structure fields around as pointers or references, there is no way for it to know these should be treated in a special manner. It will treat them as aligned data and will access them accordingly, which leads to crashes when the address is unaligned.

As marcin_j mentioned, it is possible to work around this by telling the compiler a particular pointer/reference is unaligned with the __unaligned keyword, or rather the UNALIGNED macro which does nothing on platforms that do not need it. It basically tells the compiler to be careful with the pointer in a way that I assume it similar to the way unaligned structure members are accessed.

A naïve approach would be to plaster UNALIGNED all over your code, but is not recommended because it can incur a performance penalty: any data access with __unaligned will need several memory read/writes whereas the aligned version needs only one. UNALIGNED is rather typically only used at places in the code where it is known that unaligned data will be passed around, and left out elsewhere.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top