gpt4 book ai didi

c - 对不同结构类型的指针进行类型转换是否合法(例如,将 struct sockaddr * 转换为 struct sockaddr_in6 *)?

转载 作者:太空狗 更新时间:2023-10-29 15:25:53 37 4
gpt4 key购买 nike

这是一个在struct shapestruct rectanglestruct triangle 类型的指针之间进行类型转换的程序。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

enum { RECTANGLE, TRIANGLE, MAX };

struct shape {
int type;
};

struct rectangle {
int type;
int x;
int y;
};

struct triangle {
int type;
int x;
int y;
int z;
};

struct shape *get_random_shape()
{
int type = rand() % MAX;
if (type == RECTANGLE) {
struct rectangle *r = malloc(sizeof (struct rectangle));
r->type = type;
r->x = rand() % 10 + 1;
r->y = rand() % 10 + 1;
return (struct shape *) r;
} else if (type == TRIANGLE) {
struct triangle *t = malloc(sizeof (struct triangle));
t->type = type;
t->x = rand() % 10 + 1;
t->y = rand() % 10 + 1;
t->z = rand() % 10 + 1;
return (struct shape *) t;
} else {
return NULL;
}
}

int main()
{
srand(time(NULL));

struct shape *s = get_random_shape();

if (s->type == RECTANGLE) {
struct rectangle *r = (struct rectangle *) s;
printf("perimeter of rectangle: %d\n", r->x + r->y);
} else if (s->type == TRIANGLE) {
struct triangle *t = (struct triangle *) s;
printf("perimeter of triangle: %d\n", t->x + t->y + t->z);
} else {
printf("unknown shape\n");
}

return 0;
}

这是输出。

$ gcc -std=c99 -Wall -Wextra -pedantic main.c
$ ./a.out
perimeter of triangle: 22
$ ./a.out
perimeter of triangle: 24
$ ./a.out
perimeter of rectangle: 8

您可以在上面看到程序编译并运行时没有任何警告。我试图了解将 struct shape 的指针类型转换为 struct rectangle 是否有效,反之亦然,即使这两个结构的大小不同。

如果您的回答是这无效,那么请考虑网络编程书籍通常在 struct sockaddr *struct sockaddr_in *struct sockaddr_in6 之间进行类型转换* 指针取决于套接字系列(AF_INET 与 AF_INET6),然后解释为什么这种类型转换在 struct sockaddr * 的情况下是可以的,但在上面的 情况下却不行结构形状 *。这是使用 struct sockaddr * 进行类型转换的示例。

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

int main()
{
struct addrinfo *ai;

if (getaddrinfo("localhost", "http", NULL, &ai) != 0) {
printf("error\n");
return EXIT_FAILURE;
}

if (ai->ai_family == AF_INET) {
struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr;
printf("IPv4 port: %d\n", addr->sin_port);
} else if (ai->ai_family == AF_INET6) {
struct sockaddr_in6 *addr = (struct sockaddr_in6 *) ai->ai_addr;
printf("IPv6 port: %d\n", addr->sin6_port);
}

return 0;
}

此代码也可以正常编译和运行。此外,根据有关套接字编程的书籍,这是编写此类程序的推荐方式。

$ gcc -std=c99 -D_POSIX_SOURCE -Wall -Wextra -pedantic foo.c
$ ./a.out
IPv6 port: 20480

最佳答案

Is it legal to type-cast pointers of different struct types (e.g. struct sockaddr * to struct sockaddr_in6 *)?

是的。 C明确规定:

A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer.

(C2011, 6.3.2.3/7)

正如其他答案所指出的那样,问题不在于类型转换本身,而在于您如何处理结果。这归结为严格的别名规则:

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:

  • a type compatible with the effective type of the object,

[... plus several other alternatives that cannot apply in this case ...]

(C2011,6.5/7;已强调)

因此,主要问题是 struct sockaddr * 对象的有效类型是什么?点?重要的是要了解 我们无法从 getaddrinfo() 的声明中分辨出来, 也不是 struct addrinfo。特别是,没有理由假设有效类型是 struct sockaddr .

事实上,鉴于您询问的转换是访问地址详细信息的标准和预期方法,我们有充分的理由假设 getaddrinfo()通过确保有效类型是由关联的 ai_family 指示的类型来支持这一点代码。然后相应的转换产生一个与地址信息的有效类型相匹配的指针。在这种情况下,通过强制转换获得的指针访问地址信息本身就没有问题。

我的观察支持上述观点,假设所讨论的指针指向一个动态分配的对象是合理的。此类对象的有效类型取决于上次设置其存储值的方式 (C2011, 6.5/6)。 getaddrinfo() 这不仅是合理的,而且很可能将以赋予它所需的有效类型的方式设置该值。例如,沿着与您的形状示例相同的代码行进行编码。

最终,类型转换 struct sockaddr *指向和指向地址族特定结构的指针是预期用途,没有理由假设提供 getaddrinfo() 的环境实际上,会让这些行为变得可疑。如果有必要,POSIX(指定函数的人)可以合并一个允许强制转换的特殊规则。但是在这种情况下不需要这样的规则,尽管 POSIX 让您相信它。

关于c - 对不同结构类型的指针进行类型转换是否合法(例如,将 struct sockaddr * 转换为 struct sockaddr_in6 *)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39425409/

37 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com