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