繁体   English   中英

我可以使用另一个结构中的结构成员吗?

[英]can I use struct member from another struct?

从这些问题: 将一个结构指针转换为另一个结构指针 - 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一样),有我的指针。 所以我不应该取消引用错误的地址,但我仍然不能。 为什么?

output

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结构在 memory 中看起来像这样:

| 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作为指向lambda_object的指针开始。 我们已将p类型转换为 char 指针以到达此结构中的正确偏移量,但这意味着您告诉编译器在位置p + 8处有一个字符,而实际上有一个指向字符的指针。 如果将它传递给printf() ,它会尝试将此指针作为字符串打印,从而导致乱码。

您现在应该做的是取消引用指针p + 8以通过告诉编译器将p + 8视为指向指针的指针来获取指针expression 这是通过对(char**)的类型转换来实现的。 现在您可以取消引用它一次以获得一个 char 指针,最后将它传递给printf()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM