Calmarius
Calmarius

Reputation: 19451

How can I copy small data efficiently from a char buffer without breaking the strict aliasing rules?

The answer in the another question: Strict aliasing rule and 'char *' pointers says that using a char* to examine the binary contents of a T object is ok. But using a T* to overlay on a char buffer is not ok.

Now I have a function that takes a char buffer with binary data. And does things like this while reading it:

// unsigned char *pData used to walk through the buffer.
uint32_t value = *(unit32_t*)pData;
pData += 4;

If I break the strict aliasing by doing this, what other, more effective ways available? Will compilers optimize memcpy calls when they are called with small amount of bytes?

Upvotes: 5

Views: 355

Answers (2)

user4832129
user4832129

Reputation:

Will compilers optimize memcpy calls when they are called with small amount of bytes?

For this sample code:

#define _CRT_SECURE_NO_WARNINGS // To allow usage of scanf in vc++2015
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main()
{
    // printf and scanf to prevent code elimination
    char bytes[ 4 ];
    scanf( "%s", bytes ); 
    char buffer[ 4 ];
    memcpy( buffer, bytes, 4 );
    printf( "%s", buffer );

    return 0;
}

Visual C++ 2015 generated this assembly output (release build, x64):

; memcpy was replaced by a simple register move
mov    eax, DWORD PTR bytes$[rsp] 
lea    rdx, QWORD PTR buffer$[rsp]                   ; setting arguments 
lea    rcx, OFFSET FLAT:??_C@_02DKCKIIND@?$CFs?$AA@ ; for printf call
; at this point copied array was actually stored in memory
mov    DWORD PTR buffer$[rsp], eax     
call   printf

So yes, modern compilers won't even call the procedure.

Upvotes: 2

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726967

If I break the strict aliasing by doing this ...

Yes, you do

what other, more effective ways available?

If the buffer must be char, you need to use memcpy into uint32_t before accessing the value. Of course if all your values were uint32_ts, you could make a buffer of uint32_ts, and pass it to the function that fills it with chars, because strict aliasing is a one-way prohibition, i.e. using a uint32_t* as a char* is allowed.

Will compilers optimize memcpy calls when they are called with small amount of bytes?

Many CPUs have built-in instructions for memcpy. Modern compilers use these instructions for good efficiency.

Upvotes: 3

Related Questions