4

我有以下测试程序:

#include <string.h>
int q(int *p) {
    int x;
    memcpy(&x,p,sizeof(int));
    x+=12;
    memcpy(p,&x,sizeof(int));
    return p[0];
}

当我使用 GCC 4.7.2 for arm-linux-gnueabihf 编译它时,编译器怀疑指针访问可能未对齐,在程序集输出中注释加载和存储,例如:

    ldr     r0, [r0, #0]    @ unaligned

如果我用 编译-mno-unaligned-access,编译器根本不会发出直接加载和存储,而是调用库memcpy。但实际上,这种情况下的指针永远不应该是未对齐的。这是gcc中的一个忽略,还是我弄错了?

4

4 回答 4

2

我认为gcc确实对在调用中int*被强制转换为 a感到困惑,并假设这样的指针是最坏的。它本可以尝试查看底层指针是否正确对齐。您是否尝试过更高的优化级别?可能是在更高的层次上变得更聪明。void*memcpygcc

也有可能gcc不保证int所有代码中的指针对齐,但这是不明智的,而且不太可能。

int*p由于第 6.2.3.2 和 7 条,允许编译器假设正确对齐:

指向对象类型的指针可以转换为指向不同对象类型的指针。如果结果指针未正确对齐 68) 对于引用的类型,则行为未定义。

Note 68) 是关于正确对齐的传递性。

于 2013-04-24T12:17:42.537 回答
2

在 C 编译器中,没有什么比值的加载和存储更好的优化了int,这些值在设计上是机器的自然大小。

将函数写为

int q(int *p) {
    return *p += 12;
}

这避免了对库例程的两次调用,否则您指望优化器内联并减少到简单的加载和存储,并表达就地修改整数值参数并返回结果的意图。

使用memcpy分配整数会混淆意图。

如果这个问题是将一个更大的问题减少到最小尺寸的混淆示例的结果,那么我的实现可能不会直接帮助。但即使类型psome_complex_struct *而不是int *,建议仍然适用。赋值运算符有效。memcpy在有意义的地方优先使用它。

于 2013-04-24T17:53:39.510 回答
1

如果你的linux内核版本之前到2.6.28。GCC 会抛出这个Warning-munaligned-access支持在未对齐的地址上访问内存。这需要这些系统的内核启用此类访问 或者,不支持未对齐的访问,所有代码都必须使用 -mno-unaligned-access 进行编译。上游 Linux 内核版本自动且无条件地支持由 GCC 发出的未对齐访问,因为此选项自版本 2.6.28 起处于活动状态。

于 2013-04-24T12:11:33.163 回答
1

这是我提出的解决方案,实现了一些数据字段访问的替代方案:

// #define USE_MEMCPY
// #define USE_PACKED
#ifdef __cplusplus
template <typename T> void SET(T *__attribute__((may_alias)) p, T val) {
    *p=val;
}
template <typename T> T GET(T *__attribute__((may_alias)) p) {
    return *p;
}
#else
#ifdef USE_MEMCPY
#include <string.h>
#define _SET(p,val,line) \
  ({ typeof(val) _temp_##line = (val); \
       memcpy((void*)(p),(void*)&_temp_##line,sizeof(_temp_##line)); }) 
#define _GET(p,line) \
  ({ typeof(*(p)) _temp_##line; \
       memcpy((void*)&_temp_##line,(void*)(p),sizeof(_temp_##line)); \
       _temp_##line; })

#define SET(p,val) _SET(p,val,__LINE__)
#define GET(p) _GET(p,__LINE__)
#else /* no memcpy */
#ifdef USE_PACKED
#define SET(p,val) (((struct { typeof(val) x __attribute__((packed)); } __attribute__((may_alias))*)p)->x=(val))
#define GET(p) (((struct { typeof(*p) x __attribute__((packed)); } __attribute__((may_alias))*)p)->x)
#else
#define SET(p,val) (*((typeof(val) __attribute__((may_alias))*)p)=(val))
#define GET(p) (*((typeof(*p) __attribute__((may_alias))*)p))
#endif
#endif
#endif

然后我可以这样写函数:

int q(int *p) {
    SET(p,GET(p)+12);
    return p[0];
}
于 2013-04-25T08:59:40.750 回答