在 C 中,如果我有一个:
char *ptr;
如果,比方说,ptr
指向地址 0xbfc70753
,我如何将它转换为一个 char 数组,以便我最终得到一个 char 数组 addr
将包含:
char addr[4] = "\x53\x07\xc7\xbf"
即将ptr
指向的地址转换为char数组并小端排序。
(Kali Linux,32 位,英特尔)
最佳答案
在 C 中,指针宽度(即用于表示指针的字节数)是无法保证的。您了解您的平台,因此您可以为此编写代码,但您的代码很可能无法移植。
其中一个答案中显示的技术可能有效,但它有几个弱点,
char *ptr = ...
char adr[4]; //<< Not a great idea! See below...
*(uint32_t*)adr = (uint32_t)ptr; //<< Not a great idea! See below...
第一个弱点是指针的大小可能不是 4 个字节。例如,如果您曾经在 64 位系统上运行过代码怎么办?要解决此问题,您最好使用 uintptr_t
。 C99 标准(第 7.18.1.4 节)将此类型定义为...
...an unsigned integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer...
This article很好地解释了为什么指针宽度可能因架构而异,以及 uintptr_t
、size_t
等类型如何提供帮助。
下一个可能的问题是类型别名。当两个变量指向相同的内存位时,就会发生这种情况。这是一个问题,因为 C 编译器会假定具有不同有效类型 的两个对象不会引用重叠的内存位置。
有效类型在第 6.5 节中定义为:
The effective type of an object for an access to its stored value is the declared type of the object, if any
类型转换和类型双关问题出现的地方是标准所说的(我已经改写了一些以缩短它)...
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
— a (qualified version of a) type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the (qualified) effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its members, or
— a character type.
在上面的例子中,adr
的类型是指向字符数组的指针。 32 位整数不是 compatible用字符键入。因此这违反了第一条规则,因此可能导致 UB(未定义行为)。
为什么这是个问题?在某些系统上,答案在于数据对齐。 This article在这个主题上非常有用。某些系统可能假设并要求访问 uint32_t
类型是在 4 字节对齐的边界上完成的。但是,您的 char
数组没有这样的限制。因此,如果数组开始于非 4 字节对齐的位置,则使用别名无符号整数指针访问它可能会导致硬件异常,例如。 The following article更多地讨论类型别名的其他问题,更深入,更具体地说,也与类型双关有关。
好的,那么您可以做些什么来解决这个问题呢?类似下面的内容将为您提供解决方案...
#include <stdio.h>
#include <stdint.h>
int main(void)
{
size_t i;
char const *ptr = "Some string";
char adr[sizeof(void *) + 1]; // Note the +1 to make room for NULL terminator
uintptr_t ptrAddress = (uintptr_t)ptr;
printf("Pointer address is %p\n", ptr);
printf("Converting to 0x");
for(i = 0; i < sizeof(void *); ++i)
{
adr[i] = ptrAddress & 0xff;
printf("%2.2X", (unsigned int)(unsigned char)adr[i]);
ptrAddress >>= 8;
}
printf("\n");
adr[sizeof(void *)] = '\0';
return 0;
}
现在,数组 adr
的大小将始终与您系统上的指针大小相匹配。它还将存储指针小端的值,因为地址的最低有效字节存储在第一个数组位置(最低地址)等。
关于将指针地址转换为 char 数组并使其成为小端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21482489/