![](/img/trans.png)
[英]use define to assign a struct member to another member of the same struct
[英]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.