将指针地址转换为 char 数组并使其成为小端

标签 c linux string pointers

在 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_tsize_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 的大小将始终与您系统上的指针大小相匹配。它还将存储指针小端的值,因为地址的最低有效字节存储在第一个数组位置(最低地址)等。

See working example of the above on oneide...

关于将指针地址转换为 char 数组并使其成为小端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21482489/

相关文章:

c - LD_PRELOAD不会影响RTLD_NOW的dlopen()

c - 带 malloc 的二维数组

c - make 文件中所需的帮助

c - 如何在 Linux 上按名称对某些目录中的文件进行排序

java - 如何在 Java 中比较字符串?

java - 字符串格式为特定模式

c - 在 C 中返回函数数组

c - 确定 *char < INT_MAX 是否

java - 通过 java 将文件从 Linux 服务器中的一个位置复制到另一个位置的最佳方法

python - 如何找到跨越垂直线的图案?