c - 我可以使用另一个结构中的结构成员吗?
问题描述
从这些问题:将一个结构指针转换为另一个 - C,我想知道,是否可以使用类型为“特定”结构的“通用”结构的成员:
#include <stdio.h>
#include <stdlib.h>
enum type_e { CONS, ATOM, FUNC, LAMBDA };
typedef struct {
enum type_e type;
} object;
typedef struct {
enum type_e type;
char *expression;
} lambda_object;
typedef struct {
enum type_e type;
object *car, *bus;
int value;
} cons_object;
object *traverse(object *o){
if (o->type == CONS){
cons_object *cons = (cons_object*)o;
traverse(cons->car);
traverse(cons->bus);
return (object*)cons;
} else if (o->type == LAMBDA) {
lambda_object *lam = (lambda_object*)o;
return (object*)lam;
}
return 0;
}
int main(){
lambda_object l = {LAMBDA, "value to print\n"};
object *p = traverse((object*)&l);
printf("sizeof(object):%lu\nsizeof(lambda_object):%lu\n",sizeof(object), sizeof(lambda_object));
printf("%s\n",*(p+4));
}
哪个不会发出错误,command terminated
所以我不知道出了什么问题,但怀疑我试图尊重错误的地址*(p+4)
,但我知道,有一个指向我的字符串的指针。从 的定义lambda_object
,之后enum
(它是 4 个字节长,就像int
),有我的指针。所以我不应该取消引用错误的地址,但我仍然不能。为什么?
输出:
a.c: In function ‘main’:
a.c:46:11: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘object’ {aka ‘struct <anonymous>’} [-Wformat=]
printf("%s\n",*(p+4));
~^ ~~~~~~
Press ENTER or type command to continue
sizeof(object):4
sizeof(lambda_object):16
Command terminated
编辑:我试过了(char*)p[4]
,仍然终止
解决方案
首先,就像评论中指出的许多其他人一样,这不是实现您想要实现的任何目标的理想方式。最简单和最便携的方法是使用类似((lambda_object*)p)->expression
.
至于你的代码为什么会这样,也许我可以提供一个解释。
在此之前,这是您的程序,“固定”以完全按照您想要的方式打印存储的字符串。
#include <stdio.h>
#include <stdlib.h>
enum type_e { CONS, ATOM, FUNC, LAMBDA };
typedef struct {
enum type_e type;
} object;
typedef struct {
enum type_e type;
char *expression;
} lambda_object;
typedef struct {
enum type_e type;
object *car, *bus;
int value;
} cons_object;
object *traverse(object *o){
if (o->type == CONS){
cons_object *cons = (cons_object*)o;
traverse(cons->car);
traverse(cons->bus);
return (object*)cons;
} else if (o->type == LAMBDA) {
lambda_object *lam = (lambda_object*)o;
return (object*)lam;
}
return 0;
}
int main(){
lambda_object l = {LAMBDA, "value to print\n"};
object *p = traverse((object*)&l);
printf("sizeof(object):%lu\nsizeof(lambda_object):%lu\n",sizeof(object), sizeof(lambda_object));
printf("%s\n",*((char**)((char*)p+8))); // Note the weird typecasts and p + 8 instead of 4
}
考虑到这个原因,假设一台 64 位机器,你的lambda_object
结构在内存中看起来像这样:
| Bytes 0 to 3 | Bytes 4 to 7 | Bytes 8 to 16 |
--------------------------------------------------------------
| type | padding | expression |
--------------------------------------------------------------
您应该在这里注意的是,它expression
是指向字符串的指针,而不是字符串本身。因此,即使type
只有 4 字节长,也expression
只是开始于p + 8
而不是p + 4
像人们预期的那样。从 4 到 7 的字节将简单地留空作为填充。这是因为 64 位指针必须从 64 位对齐的地址开始。
但是((char *)p + 8)
应该工作对吗?不幸的是没有!我们从p
指向 a 的指针开始lambda_object
。我们已将类型转换p
为 char 指针以到达此结构中的正确偏移量,但这意味着您正在告诉编译器该 location 有一个字符,p + 8
而实际上有一个指向字符的指针。如果您将其传递给printf()
它,它会尝试将此指针作为字符串打印,从而导致乱码。
您现在应该做的是通过告诉编译器将指针视为指向指针的指针来取消引用指针p + 8
以获取指针。这是使用类型转换来实现的。现在您可以取消引用它一次以获得一个 char 指针,最后将它传递给.expression
p + 8
(char**)
printf()
推荐阅读
- java - 无法使用 selenium webdriver 启动 chrome 浏览器
- angular - ag-grid 中的自定义过滤器在 Angular 10 应用程序中不起作用
- python - “GET”请求在 Python 中工作,但在机器人框架中不起作用
- swift - Swift 控制台打字动画
- r - glmmTMB 警告信息
- php - 如何使用名称、日期和数量对数组进行排序?PHP
- php - 如果为空,则归档 Acf 数值 显示消息
- firebase - 限制 Google Firebase 对特定 HTTP 引荐来源网址的访问
- jsf - Quarkus 和 Primefaces 无法让 PrettyFaces 运行
- wordpress - 使用 AJAX 调用更新自定义字段后,Wordpress 更新 CustomFields 部分