簡體   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