У меня есть указатель на uint8_t
. Я знаю, что он выровнен по адресу 4. Я хочу быстро читать и писать туда uint32_t
значение.
Правильный по стандарту вариант использовать memcpy
, но он очень медленный.
Быстрый вариант - кастовать uint8_t *
в uint32_t *
и полагаться на то, что он выровнен. Это генерирует одну инструкцию, но это UB по стандарту, хотя по факту работать будет…
Как тут можно поступить? Меня интересует конкретный компилятор gcc 9.2. Может быть gcc даёт какие-то дополнительные гарантии сверх стандарта для данного случая?
Код:
#include <stdint.h>
#include <string.h>
void save1(uint8_t *p, uint32_t v) {
memcpy(p, &v, 4);
}
void save2(uint8_t *p, uint32_t v) {
uint32_t *p32 = (uint32_t *)p;
*p = v;
}
uint32_t load1(uint8_t *p) {
uint32_t v;
memcpy(&v, p, 4);
return v;
}
uint32_t load2(uint8_t *p) {
uint32_t *p32 = (uint32_t *)p;
return *p32;
}
Во что он компилируется с -Os:
save1:
push {r0, r1, r2, lr}
mov r2, #4
str r1, [sp, #4]
add r1, sp, r2
bl memcpy
add sp, sp, #12
ldr lr, [sp], #4
bx lr
save2:
strb r1, [r0]
bx lr
load1:
push {r0, r1, r2, lr}
mov r2, #4
mov r1, r0
add r0, sp, r2
bl memcpy
ldr r0, [sp, #4]
add sp, sp, #12
ldr lr, [sp], #4
bx lr
load2:
ldr r0, [r0]
bx lr