gpt4 book ai didi

c - C 中的强制转换结构中的段错误

转载 作者:行者123 更新时间:2023-11-30 14:47:59 25 4
gpt4 key购买 nike

为了封装结构成员(以类似于 this 问题中讨论的方式),我创建了下面的代码。

在下面的代码中,我有一个 c 结构,其中包含访问隐藏结构成员的方法(通过转换为结构,否则相同但没有隐藏属性)

#include <stdio.h>

typedef struct class {
int publicValue;
int (*getPV)();
void (*setPV)(int newPV);
} class;

typedef struct classSource {
int publicValue;
int apv;
int (*getPV)();
void (*setPV)(int newPV);
int PV;
} classSource;

class class_init() {
classSource cs;
cs.publicValue = 15;
cs.PV = 8;
int class_getPV() {
return cs.PV;
};
void class_setPV(int x) {
cs.PV = x;
};
cs.getPV = class_getPV;
cs.setPV = class_setPV;
class *c = (class*)(&cs);
return *c;
}


int main(int argc, const char * argv[]) {
class c = class_init();
c.setPV(3452);
printf("%d", c.publicValue);
printf("%d", c.getPV());
return 0;
}

当我运行这个程序时,我收到段错误错误。但是,我注意到,如果我注释掉某些代码行,它(似乎)可以正常工作:

#include <stdio.h>

typedef struct class {
int publicValue;
int (*getPV)();
void (*setPV)(int newPV);
} class;

typedef struct classSource {
int publicValue;
int apv;
int (*getPV)();
void (*setPV)(int newPV);
int PV;
} classSource;

class class_init() {
classSource cs;
cs.publicValue = 15;
cs.PV = 8;
int class_getPV() {
return cs.PV;
};
void class_setPV(int x) {
cs.PV = x;
};
cs.getPV = class_getPV;
cs.setPV = class_setPV;
class *c = (class*)(&cs);
return *c;
}


int main(int argc, const char * argv[]) {
class c = class_init();
c.setPV(3452);
//printf("%d", c.publicValue);
printf("%d", c.getPV());
return 0;
}

我认为这可能与使用初始化程序将 getter 和 setter 方法添加到结构有关,因为这些方法可能会覆盖内存。

我正在做的事情是未定义的行为吗?有办法解决这个问题吗?


编辑:在下面的答案的帮助下,我重新编写了代码。如果有人想查看实现,下面是修改后的代码

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

typedef struct {
int pub;
} class;

typedef struct {
class public;
int PV;
} classSource;

int class_getPV(class *c) {
return ((classSource*)c)->PV;
}

void class_setPV(class *c, int newPV) {
((classSource*)c)->PV = newPV;
}

class *class_init() {
classSource *cs = malloc(sizeof(*cs));
if((void*)cs == (void*)NULL) {
printf("Error: malloc failed to allocate memory");
exit(1);
}
cs->public.pub = 10;
cs->PV = 8;
return &(cs->public);
}

int main() {
class *c = class_init();
class_setPV(c,4524);
printf("%d\n",class_getPV(c));
printf("%d\n",c->pub);

free(c);
return 0;
}

最佳答案

您的代码中至少存在三个单独的问题。

  1. 您实际上并没有“结构在其他方面相同但没有隐藏属性”。您的classclassSource结构有其 getPVsetPV成员在不同的地方。内部成员访问归结为距结构开头的字节偏移量。为了有更好的工作机会,您的代码需要在两个结构类型之间有一个共同的成员初始前缀(即去掉 int apv; 或将其移到末尾)。

  2. 您将按值返回一个结构,它会自动创建一个副本。您已经重新实现了 object slicing问题:因为返回值的类型为 class ,仅 class 的成员将被复制。 classSource的额外成员已被“切掉”。

  3. 您正在使用嵌套函数。这不是 C 的标准功能; GCC implements it as an extension并说:

    If you try to call the nested function through its address after the containing function exits, all hell breaks loose.

    这正是您的代码中发生的情况:您正在调用 c.setPV(3452);c.getPV之后class_init已经回来了。

如果您想解决这些问题,您必须:

  1. 修复您的结构定义。至少 class 的所有成员需要出现在classSource开头以相同的顺序。即使您这样做,我不确定您是否仍然会遇到未定义的行为(例如,您可能违反了别名规则)。

    但是,我有点确定将一个结构嵌入到另一个结构中是可以的:

    typedef struct classSource {
    class public;
    int PV;
    } classSource;

    现在您可以返回&cs->public从你的初始化程序中,你的方法可以强制转换 class *指针返回classSource * 。 (我认为这是可以的,因为所有结构体指针都具有相同的大小/表示形式,并且 X.public 作为第一个成员保证具有与 X 相同的内存地址。)

  2. 更改代码以使用指针。返回指向结构的指针可以避免切片问题,但现在您必须处理内存管理(malloc 结构,稍后再处理 free)。

  3. 不要使用嵌套函数。相反,将指向对象的指针传递给每个方法:

    class *c = class_init();
    c->setPV(c, 3452);
    int x = c->getPV(c);

    这有点乏味,但这就是例如C++ 本质上是在幕后做的。除了 C++ 不将函数指针放入对象本身之外;没有理由什么时候您可以使用正常功能:

    setPV(c, 3452);
    int x = getPV(c);

    ...或使用单独的(全局、常量、单例)结构,仅存储指向方法的指针(不存储数据)。每个对象只包含一个指向该方法结构的指针(这称为 vtable):

    struct classInterface {
    void (*setPV)(class *, int);
    int (*getPV)(const class *);
    };
    static const classInterface classSourceVtable = {
    class_setPV, // these are normal functions, defined elsewhere
    class_getPV
    };

    方法调用如下所示:

    c->vtable->setPV(c, 1234);
    int x = c->vtable->getPV(c);

    但是,如果您有多个共享公共(public)接口(interface) ( class ) 的不同结构类型,并且您希望编写在所有这些类型上统一工作的代码,那么这非常有用。

关于c - C 中的强制转换结构中的段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50822048/

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