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

mor*_*imn 5 c void-pointers language-lawyer

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

6.2.5.27:

指向 void 的指针应具有与指向字符类型的指针相同的表示和对齐要求。39) 类似地,指向兼容类型的限定或非限定版本的指针应具有相同的表示和对齐要求。

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

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

相同的表示和对齐要求意味着作为函数参数、函数返回值和联合成员的可互换性。

我的问题是:

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

  2. 如果是这样,它是编译器进行的隐式转换吗?

  3. 那么工会成员又是什么呢?我实在不明白这句话的意思。谁能给我一个简单的例子吗?

chq*_*lie 7

在 C 中,任何数据指针都可以传递给需要 a 的函数void *,并且 avoid *可以存储为任何指针类型。void *和其他指针类型之间存在隐式转换。但这并不意味着这种转换是无害的。在某些体系结构中void *, 和int *具有不同的表示形式,从int *to转换void *然后返回 toint *被指定为产生相同的指针值,但反之则不成立:将 a 转换void *int *并返回 tovoid *可能会产生不同的值,特别是如果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;
}
Run Code Online (Sandbox Code Playgroud)

但请注意,这并不意味着这一点,!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)); 纠正 ifsizeof(int) == sizeof(float)但可能会产生陷阱值。