在 C 语言中:我可以让两个不同类型的指针指向同一个地址吗?

Posted

技术标签:

【中文标题】在 C 语言中:我可以让两个不同类型的指针指向同一个地址吗?【英文标题】:In C: Can I have two pointers of different types pointing to the same address? 【发布时间】:2022-01-23 21:36:40 【问题描述】:

问题:

我可以让两个不同类型的指针(uint32_t *char *)指向同一个地址吗?


这就是我想要这个的原因:

我想在C 中将UTF-8 转换为UTF-32,反之亦然。

可以说,我有一个 uint32_t 类型的变量,其中包含一个 UTF-32 编码的 unicode 字符。而且我已经知道以 UTF-8 编码时它需要 4 个字节。它的二进制表示是这样的:

00000000000aaabbbbbbccccccdddddd

a、b、c 和 d 是 4 个不同的范围,其中每个位可以是 0 或 1。 通过巧妙的按位 &|<< 操作,我可以重新排列这些位,以便最后有这个新的分布:

00000aaa00bbbbbb00cccccc00dddddd

然后我可以翻转一些位(再次使用|)来得到这个

11110aaa10bbbbbb10cccccc10dddddd

当我将其拆分为数组中的 4 个后续 char 变量时,我有这个:

11110aaa  10bbbbbb  10cccccc  10dddddd

这正是同一个 unicode 字符的 UTF-8 编码。

因此,内存中相同的 4 个字节应该是一个 uint32_t 变量,同时是一个由 4 个 char 变量组成的数组:

所以,我想要这个:

uint32_t *utf32;
char utf8[4];

*utf32 是一个指向单个 4 字节长的 uint32_t 变量的指针。 utf8 是一个指向由 4 个 char 元素组成的数组的指针,每个元素长 1 个字节。

我希望两个指针都指向同一个地址。所以我可以将一个 utf32 编码的字符写入变量utf32,将其转换到位,然后从数组utf32 中读取结果。这可能吗?如果是这样:我该怎么做?

(我在上个千年用 COBOL 编码时经常使用这种技术,因为在 COBOL 中很容易用许多不同的定义重载内存中的同一区域。但我不知道如何在C.)


我发现很多问题涉及指向相同地址的 2 个指针,但在这些问题中,指针始终具有相同的类型。还有一些其他问题是,如果用某种类型定义的指针指向用另一种类型定义的地址,为什么会出现错误。但是我没有发现任何关于共享同一地址的两个不同类型的指针。

【问题讨论】:

"因此,内存中相同的 4 个字节应该是一个 uint32_t 变量,同时是一个由 4 个 char 变量组成的数组" - 而那当然可能(如您所问,通过使用union 或2 个指向同一内存的类型指针),我不建议这样做。 uint32_t 具有字节顺序,其字节顺序可能与您需要的 char[] 顺序不匹配。我将使用单独的char[] 并根据需要将位从uint32_t 移到char[],而不管字节序如何。此外,由于 UTF-8 无论如何都是可变长度的,并非所有 uint32_t 值都会填充 char[4] 你可以这样做——但你的两个指针之一将是char *,这很有帮助。如果你有两个不是char * 的指针——比如int *float *——你就不得不担心strict aliasing。但是通过char 类型访问是该规则的明确例外。 【参考方案1】:

我可以让两个不同类型的指针(uint32_t * 和 char *)指向同一个地址吗?

是的,你可以。

union U 
  uint32_t ui32;
  char c[4];
;

union U u;
u.ui32 = ...

uint32_t *pi = &u.ui32;
char *cp = u.c;

assert(pi == cp);

如果您使用生成的char* 来执行除了将数据复制入或复制出之外的其他操作,您将违反一些 C 语言规则,但“指向同一地址的两个不同指针类型”不是问题本身。

您也可以简单地将地址转换为所需的类型:

uint32_t x;
uint32_t *ip = &x;
char *cp = (char*)&x;

assert(ip == cp);

【讨论】:

虽然union 有效,但没有必要。如果存储的内存是 uint32_t 类型(或兼容),只需将其指针转换为 char* 即可。【参考方案2】:

是的,两个不同类型的指针可以指向同一个地址。

假设你记忆中的某个地方是这个 utf32,你知道它在哪里,所以我将它称为address

因此,如果您想将这 4 个字节视为 uint32,您可以这样做:

uint32_t* utf32 = address;

您可以将 is 视为 char 数组:

char* utf8 = address;

如果你想访问一个字符,你只需这样做:

utf8[index]

【讨论】:

以上是关于在 C 语言中:我可以让两个不同类型的指针指向同一个地址吗?的主要内容,如果未能解决你的问题,请参考以下文章

c语言指针知识点总结

c语言如何将两个变量关联起来

C 语言const 关键字用法 ( 常量指针 - const 在 * 左边 - 修饰数据类型 - 内存不变 | 指针常量 - const 在 * 右边 - 修饰变量 - 指针不变 )

在C语言中能否直接给指针指向的数据赋值?为啥?

指向匿名联合成员的指针是不是相等?

C语言指针/引用/取值