在C语言中减少返回/传递的数据结构的大小

在C语言中减少返回/传递的数据结构的大小,c,C,我在麻省理工学院在线学习操作系统课程,我完成了第一个作业但令我惊讶的是,他们如何返回数据结构,他们使用数据结构,返回一个较小的数据结构,为了使用它,他们只是将其抛回。我看到它可以优化代码,但这是安全的吗?这是个好习惯吗 #include <stdio.h> #include <string.h> #include <stdlib.h> struct small { int n ; }; struct big { int n ; c

我在麻省理工学院在线学习操作系统课程,我完成了第一个作业
但令我惊讶的是,他们如何返回数据结构,他们使用数据结构,返回一个较小的数据结构,为了使用它,他们只是将其抛回。我看到它可以优化代码,但这是安全的吗?这是个好习惯吗

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

struct small
{
    int  n ;
};

struct big
{
    int n ;
    char * string ;
};

struct small* f()
{
    struct big* x = malloc(sizeof(struct big));
    x->n = 'X';
    x->string = strdup("Nasty!");
    return (struct small*) x ;
}

int main(int argc, char *argv[])
{
    struct big *y = (struct big*)f();
    printf("%s\n",y->string);
}
#包括
#包括
#包括
结构小型
{
int n;
};
结构大
{
int n;
字符*字符串;
};
结构小*f()
{
struct big*x=malloc(sizeof(struct big));
x->n='x';
x->string=strdup(“讨厌的!”);
返回(结构小*)x;
}
int main(int argc,char*argv[])
{
结构大*y=(结构大*)f();
printf(“%s\n”,y->string);
}
编辑1:这是麻省理工学院的链接,我刚刚在自己的代码中复制了这个想法。

是的,只要编译器遵循C标准,它是安全的

但是,我不认为这是一个好的实践。 好的实践是相对的,永远不应该作为规则使用。如果要用C模拟OO继承行为,则需要此构造

  • 不返回结构,但返回指向结构的指针。指针包含实际对象所在的内存地址。(在这种情况下,它是使用
    malloc
    动态分配的,因此具有动态存储持续时间,并将一直持续到pogram结束或在指针上调用
    free

  • 该代码是合法的,并定义了语义。n1570草案的6.3.2.3/7规定

    指向对象类型的指针可以转换为指向对象类型的指针 不同的对象类型。如果生成的指针不正确 与引用的类型对齐,行为未定义。[此处不适用。-ps] 否则,当再次转换回时,结果应相等 指向原始指针

  • 请注意,这些结构可能完全不相关(第一个数据元素不需要是相同的类型)。强制转换甚至可以是内置类型,如
    int


    如果由于别名问题而通过错误类型的指针(不是)访问对象,则问题可能不同。

    要回答您的问题:

    安全吗

    显然不是。只有在确定指针类型正确的情况下,才应该将指针类型转换为其他类型

    然而,如果你知道这一点,一切都很好

    这是个好习惯吗

    不,不是这个形状

    有时,您会以类似的方式在C中进行面向对象编程(比较CPython的
    PyObject
    ):您使用一个“基本”对象和一个“类型”结构,其结构如下:

    struct obj_type {
      const char* name;
      size_t length; // this is important so that you can copy the object later on without knowing its insides
    };
    
    struct obj_base {
      obj_type* type;
    };
    
    因为可以保证在C中,指向结构的指针指向其第一个元素的地址,所以您可以使用构建在其上的其他对象:

    struct more_complex_object {
      obj_type* type; 
      int value;
    };
    
    ...
    int main() {
      obj_type *more_complex_object_type = malloc(sizeof(obj_type));
      more_complex_object_type->name = "A more complex object type";
      more_complex_object_type->length = sizeof(more_complex_object);
      more_complex_object *obj = malloc(more_complex_object_type->length);
      obj->type = more_complex_object_type;
      obj->value = 10;
      ...
      //let's now use it as a simple instance of the "super" object
      obj_base* just_an_object = (obj_base*)more_complex_object;
      //when we copy things, we make sure to copy the full length:
      obj_base* target = malloc(sizeof(more_complex_object));
      memcpy(target, just_an_object, just_an_object->type->length);
    
      //now, when handling an object, we can check its type
      if(just_an_object->type == more_complex_object_type) {
        more_complex_object *my_obj = (more_complex_object)just_an_object;
        printf("value: %d\n", my_obj->value);
      }
    }
    

    除此之外,我认为这是一个糟糕的代码。它们不返回结构,而是返回一个结构的地址。我甚至不确定这是否是定义好的行为——如果演员在
    void*
    之间来回走动,我会更高兴。但是在C语言中,地址的数值不会随着类型转换而改变,所以它是有效的。也许这里我遗漏了一些东西,但我完全不明白其中的意义。在C中返回结构通常由编译器通过简单地传递一个隐藏指针到调用方堆栈上分配的
    struct
    来实现,但这里的情况甚至不是这样,因为它们在指针周围移动。对我来说,这看起来像是应该避免的坏习惯(毫无意义,即没有任何好处)。除此之外,这是一种未定义的行为,因为人们只能在
    void*
    之间进行转换。这不仅可怕,而且没有必要。它返回一个指针,不管它指向什么,指针的大小都是一样的。这看起来像是在没有C++的
    private
    关键字的情况下试图隐藏信息。@szczurcio传递和返回C中的结构(只要允许,即post-K&R)总是具有值语义。这里没有秘密指针。Peter的答案解决了这个问题OK这是合法的,但是如果我的程序多次调用malloc并释放,它不会损坏为字符串变量保留的内存吗?
    malloc
    /
    free
    对数据类型不敏感(除了malloc返回的内存可以保存要求最高的类型对齐方式外)。它们只保存位置簿和从那里开始的最终需要释放的字节数。指针
    字符串
    指向“讨厌的”不会受到malloc和free的影响。但是您必须
    free
    内存
    字符串
    指向,因为它已通过
    strdup
    动态分配。我有一种预感,您仍然认为该对象在某种程度上被演员“剪短”或“修剪”。我可以向您保证它不会受到影响;-).我知道施法不会缩短时间,分配和释放内存可以做到这一点。但现在我明白了,因为它是分配的,而不是释放的,所以它不会被另一个malloc触及。谢谢您的时间,谢谢您的解释。只要您不访问未分配的内存,就没有危险。您可以将任何类型指针传递到
    free
    ——其参数声明为
    void*
    。不考虑该指针类型。
    malloc
    free
    不关心内存的使用以及使用的指针。对象内存大小的簿记是在后台完成的(确切地说,只是存储在分配的块之间的空间中)。(注意C++中的情况有很大不同)它和C.@彼得拉施奈德中的任何东西一样安全:是的,只要你不把一些东西投到实际上不是“兼容类型”的东西上,你就说了所有的话,我很感激你的回答,我真的不太感谢你,先生。而(1){谢谢;}你的例子