我正在制作一个内存块复制例程,需要以高效的块来处理原始内存块。我的问题不是关于我正在制作的专门复制例程,而是关于如何在C中正确检查原始指针对齐。
我有一个内存的原始指针,假设它已经被转换为非空的char *。 在我的架构中,当它与64字节块相对应时,我可以非常高效地以64字节块的形式复制内存。所以(标准)技巧是我将在头部和/或尾部“手动”执行0-63字节的简单复制,以将副本从任意长度的任意字符*转换为具有某些倍数的64字节对齐指针长度为64个字节。
现在的问题是,你如何合法地“检查”一个指针来确定(和操纵)它的对齐方式? 显而易见的方法是将其转换为整数并检查位:
char *pointer=something.
int p=(int)pointer;
char *alignedPointer=(char *)((p+63)&~63);
注意这里我意识到alignedPointer并没有指向与指针相同的内存......这是我可以称之为高效复制例程的“向上舍入”指针,我将处理其他任何字节。手动开始。
但是编译器(理所当然)会把指针转换为整数。但是我怎样才能检查和操纵 LEGAL C中指针的低位?理想情况下,对于不同的编译器,我不会得到任何错误或警告。
答案 0 :(得分:7)
对于足以容纳指针的整数类型,C99 stdint.h
具有:
uintptr_t
intptr_t
对于数据长度,有:
size_t
ssize_t
自C99之前就已存在。
如果您的平台没有这些,您可以通过仍然使用这些类型名称并为它们制作合适的typedef
来最大化代码的可移植性。
答案 1 :(得分:1)
我不认为过去人们不愿意做自己的位敲击,但也许当前“不要碰那种”情绪会有利于某人创建某种标准库来对齐指针。缺乏某种官方api,你别无选择,只能通过AND和OR来完成。
答案 2 :(得分:0)
尝试一种保证与指针大小相同的数据类型(Win32 / 64上的INT_PTR),而不是int。也许编译器不会太过恐慌。 :)或者使用union,如果64位兼容性不重要。
答案 3 :(得分:0)
在整数中转换指针是有效的,但结果是实现定义的。见标准第6.3.2.3节。意图似乎是结果是任何熟悉系统的人所期望的结果,事实上这似乎是实际情况。
如果所讨论的体系结构可以交替地有效地操作指针和整数,问题在于它是否适用于该系统的所有编译器,那么答案是它可能无论如何都会。
(当然,如果我正在编写这段代码,我会认为它是正常的,直到证明不是。我的经验是,给定系统的编译器在这种级别上都表现得非常相似;汇编语言只是建议一种特殊的方法,然后再采取。)
“可能工作”虽然不是很好的一般建议,所以我的建议只是编写有效的代码,将它包围得足够合适#ifdef
s,只有已知的编译器才能编译它,并在其他情况下推迟到memcpy
。
#ifdef
很少是理想的,但与其他可能性相比,它相当轻巧。如果需要实现定义的行为或特定于编译器的技巧,那么无论如何选项都非常有限。