void* 与 char* 具有相同的表示和内存对齐是什么意思?

What does it mean that void* has the same representation and memory alignment as char*?

我一直在阅读一些关于 void* 类型指针的文章,并从标准中找到了这个要求。

6.2.5.27:

A pointer to void shall have the same representation and alignment requirements as a pointer to a character type.39) Similarly, pointers to qualified or unqualified versions of compatible types shall have the same representation and alignment requirements.

我看到标准不保证所有指针类型都具有相同的长度,所以这里的底线是 void* 指针具有与 char* 相同的长度和对齐规则,对吧?

我不明白的是脚注 39),它说

The same representation and alignment requirements are meant to imply interchangeability as arguments to functions, return values from functions, and members of unions.

我的问题是:

  1. “互换性”是什么意思?它是否表示函数 void* Func(void*) 的参数和 return 值都可以是 char*

  2. 如果是,是否是编译器隐式转换?

  3. 工会会员是怎么回事?我真的不明白这句话的意思。谁能给我一个简单的例子吗?

在 C 中,任何数据指针都可以传递给需要 void * 的函数,并且 void * 可以存储到任何指针类型。 void * 和其他指针类型之间存在隐式转换。但这并不意味着这种转换是无害的。在某些 void *int * 具有不同表示的体系结构上,从 int * 转换为 void * 然后返回 int * 被指定为生成相同的指针值,但反过来不成立:将 void * 转换为 int * 并返回 void * 可能会产生不同的值,特别是如果 void * 不是通过转换 int *.

互换性意味着这种隐式转换不会改变指针的表示形式。转换可以通过两种方式成功进行:将字符指针转换为 void * 并返回生成相同的指针,反之亦然。

这是一个例子:

#include <assert.h>
#include <stdio.h>
#include <string.h>

int main() {
    char *s = "abc";
    char *s1;
    void *p;
    void *p1;

    assert(sizeof(p) == sizeof(s));
    memcpy(&p, &s, sizeof(p));
    p1 = s;
    assert(p == p1);
    memcpy(&s1, &p1, sizeof(s1));
    assert(s == s1);
    return 0;
}

但是请注意,这并不意味着 !memcmp(&p1, &s, sizeof(p1)) 因为指针可以有填充位。您也不能通过 void *:

强制转换来违反严格的别名规则
  • float f = 1.0; unsigned int i = *(int *)(void *)&f' 不正确。
  • float f = 1.0; unsigned int i; memcpy(&i, &f, sizeof(i)); 如果 sizeof(int) == sizeof(float) 正确,但可能会产生陷阱值。

指针只是内存中的一个地址。你可以认为内存是一个字节的连续区域,它非常大(例如,在 32 位进程上它将是 4 GB,但通常进程不能使用整个取决于系统)。

这意味着指针的值实际上是一个整数,表示内存中字节的从零开始的索引(例如,值为 0 的指针指的是内存中的第一个字节,但实际上你将无法取消引用该地址,因为它是空指针)。

当您取消对指针的引用时,它所做的是 reading/writing 指向该地址。 read/write 的大小取决于指针的类型。如果指针是 int 并且它在该系统上的大小是 32 位,即 4 个字节;它将 read/write 4 个字节从该地址开始。对齐意味着值如何存储在内存中。假设存储在内存中的值需要是 16 字节对齐,这意味着它的起始地址必须乘以 16.

我这里讲解的只是指针的高阶,入门应该够用了。实际上它有很多与之相关的东西,比如内存保护、分页等。