什么是打字?类型惩罚如何与C中的工会一起使用?

Emb*_*ser 0 c type-punning

任何人都可以解释什么是C中的类型惩罚,并通过简单的示例程序演示何时出现此类问题?

我在许多网站(甚至维基)都进行了搜索,但即便如此,我也无法理解.

Sel*_*bor 6

Punning类型是一个广泛的概念,适用于任何具有类型系统和一点灵活性的语言,所以我使用维基百科的例子与Berkeley套接字:

从维基百科页面:

在Berkeley套接字界面中可以找到一个典型的类型惩罚示例.将已打开但未初始化的套接字绑定到IP地址的函数声明如下:

int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);

bind函数通常调用如下:

struct sockaddr_in sa = {0};
int sockfd = ...;
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
bind(sockfd, (struct sockaddr *)&sa, sizeof sa);
Run Code Online (Sandbox Code Playgroud)

Berkeley套接字库基本上依赖于以下事实:在C中,指向struct sockaddr_in的指针可以自由转换为指向struct sockaddr的指针; 此外,两种结构类型共享相同的内存布局.因此,对结构字段my_addr-> sin_family(其中my_addr的类型为struct sockaddr*)的引用实际上将引用字段sa.sin_family(其中sa的类型为struct sockaddr_in).换句话说,套接字库使用类型punning来实现一种基本的继承形式.

编辑:我没有注意到你提到尝试维基百科的编辑.我认为在这种情况下你应该拿走的是我在第一句中所说的,即"类型Punning是一个广泛的概念,适用于任何具有类型系统和一点灵活性的语言".如果你遇到问题,我会说要寻找更多的策略示例和实现(也许在C中看一下OOP来获得一些涉及的概念[它本身并不完全相同])

另一个编辑:它发生在我身上,也许你的意思是在工会的背景下打字,所以这里是一个修改了这个问题的例子,它询问了工会的目的(在这里向后工作):

union RGB
{
    uint32_t color;

    struct componentsTag
    {
        uint8_t b;
        uint8_t g;
        uint8_t r;
    } components;

} pixel;

pixel.color = 0x020406;
uint8_t rVal = pixel.components.r; //this will equal 02
uint8_t gVal = pixel.components.g; //this will equal 04
uint8_t bVal = pixel.components.b; //this will equal 06
Run Code Online (Sandbox Code Playgroud)

这里使用类型双关语来允许访问每种颜色的各个值而无需C类型的转换.您可能想知道这是如何工作的.在内存中,union占用32位.当sockaddr_in使用该行设置时sockaddr,这些32位填充值0x020406(0x后的每对值占用8位(8*3 = 32位).

将32位分成部分的图表可能如下所示:

------------------------------------
-----| 00  | 02  | 04  | 06  |------
------------------------------------
     |    uint32_t color     |
------------------------------------
Run Code Online (Sandbox Code Playgroud)

但组件的结构也在同一空间中占用32位.

所以现在联盟内存的完整图表是:

------------------------------------
-----| 00  | 02  | 04  | 06  |------
------------------------------------
     |    uint32_t color     |
------------------------------------
-----| NA  |  r  |  g  |  b  |------
------------------------------------
Run Code Online (Sandbox Code Playgroud)

注意如何my_addr->sin_family,my_addrstruct sockaddr*,所有重叠sa.sin_family.访问sa,struct sockaddr_incolor现在访问特定部分pixel.color = 0x020406,它的一个8比特部分.正常情况下,uint32_t的转换为uint8_t只会给你uint32_t的的最低显著位,所以0x00020406,0x06都会变得毫无意义的数字.但正如我之前所说,此处联合被用于类型惩罚,因此标准定义的转换正在被规避.