结构有什么特别之处?


81

我知道在C语言中,我们不能从函数返回数组,而只能返回指向数组的指针。但是我想知道有什么特别之处structs,即使它们可能包含数组,它们也可以由函数返回。

为什么struct包装使以下程序有效?

#include <stdio.h>

struct data {
    char buf[256];
};

struct data Foo(const char *buf);

int main(void)
{
    struct data obj;
    obj = Foo("This is a sentence.");
    printf("%s\n", obj.buf);
    return 0;
}

struct data Foo(const char *buf)
{
    struct data X;
    strcpy(X.buf, buf);
    return X;
}

1
您可以使用进行相同的操作union。工会有什么特别之处?
user253751 '16

19
您应该问为什么数组在C
语言中

当返回一个结构体时,如果该结构体不适合几个寄存器,那么将由编译器分配一个“隐藏”内存,将该结构体(通过memcpy())复制到隐藏内存中,然后再次复制(通过memcpy() ))调用方的结构变量。“隐藏”的内存丢失给所有其他功能。两次额外的调用memcpy()以及“隐藏”内存的丢失是structpassed to既不returned from是函数也不是函数的主要原因。最佳策略是将指针传递给该结构。
user3629249 '16

这三个答案都没有解决结构体的传递问题(而是仅讨论传递数组),但它们没有回答问题。
user3629249 '16

1
@ user3629249-无法回答该问题,因为该问题是基于缺乏理解的前提。回答问题的唯一方法是尝试解释为什么不能提出问题。想象一下,如果我问你“为什么蓝色和红色的颜色相同?” 您将很快解释为什么您无法回答该问题。
霍根

Answers:


100

提出相同问题的一种更好的方法是“数组有什么特别之处”,因为是数组具有附加的特殊处理,而不是structs。

通过指针传递和返回数组的行为可以追溯到C的原始实现。数组“衰减”到指针,引起了很多混乱,尤其是在刚接触该语言的人们中。另一方面,结构的行为类似于内置类型,例如ints,doubles等。这包括嵌入在中的任何数组struct,但灵活的数组成员除外,这些数组不会被复制。


4
确实“造成了很多混乱”。“ x”和“&x”具有相同的值/地址有点疯狂。毫不奇怪,新手会间接地出错:(
Martin James

1
我的记忆可能在欺骗我,但是难道不是没有时候struct按值传递s吗?
2016年

5
@alk我认为,当将结构首次添加到语言中时,最初在将它们传递给函数/从函数返回时存在一些限制,但是这些明显地被标记为编译器中的缺陷,可以很快纠正,而不是指示。想要通过并返回它们有什么问题。
史蒂夫·萨米特

8
@jamesqf :struct Point {short x, y, z;};。您真的要使用指针来移动它们吗?您当然不是这样节省空间的。
Mark VY

6
@jamesqf我不确定这是否值得回应。如果您认为C不仅仅是汇编,那么如果您从来没有理由不使用指针,那么我也许可以看到您可能会认为传递结构是无用的。但是对于我们其余的人来说,他们将C视为高级语言(就像HLL一样是低级语言),并且将C的类型系统视为通用语言(指出的第二类数组状态除外) ),为什么我们希望传递或返回结构?(BTW,IIRC,K&R1表示结构传递正在进行中,并且在本书出版时已在V7 cc中运行。)
Steve Summit

38

首先,引用C11第6.8.6.4章的return声明,(重点是我的

如果return执行带有表达式的语句,则表达式的将作为函数调用表达式的值返回给调用方。

返回结构变量是可能的(也是正确的),因为返回了结构。这类似于返回任何原始数据类型(int例如return)。

另一方面,如果使用返回数组,则return <array_name>它实际上将返回数组NOTE的第一个元素地址,如果该数组位于被调用函数的本地,则在调用方中该地址无效。因此,以这种方式返回数组是不可能的。

因此,TL; DR,没有什么特别的structS,专业是阵列


注意:

C11再次引用第6.3.2.1节(我的重点

除非它是运算sizeof符,_Alignof运算符或一元运算&符的操作数,或者是用于初始化数组的字符串文字,否则类型为“ array of type”的表达式将转换为类型为“''的表达式类型指针''指向数组对象的初始元素,不是左值。[...]


OTOH到底是什么?

1
@Sukl是“另一方面”的缩写:)
Sourav Ghosh

1
@Sukl我认为这些缩写大约和互联网本身一样古老。在Usenet辉煌的日子里,它们肯定使用了很多,并且在大多数论坛中仍然存在。值得庆幸的是,即使对于不知道的情况,谷歌也可以对它们进行解码;-)如今只有少数几个(最常用的)被频繁使用
CHI

@chi是。Google非常出色,能够解码它们。

1
@Sukl:您可能会发现AcronymFinder对于跟踪首字母缩略词很有用。
乔纳森·勒夫勒

11

struct类型没有什么特别的。数组类型有一些特殊之处,可以防止直接从函数中返回它们。

struct表达式视为任何其他非数组类型的表达式;它评估的价值struct。所以你可以做类似的事情

struct foo { ... };

struct foo func( void )
{
  struct foo someFoo;
  ...
  return someFoo;
}

表达式的someFoo计算结果struct foo对象的;对象的内容从函数返回(即使这些内容包含数组)。

数组表达式的处理方式有所不同;如果它不是sizeofor或一元运算&符的操作数,或者它不是用于在声明中初始化另一个数组的字符串文字,则表达式将从“ array of T”类型转换(“ decays”)到“ pointer to T” ,表达式的值是第一个元素的地址。

因此,您不能从函数中按值返回数组,因为对数组表达式的任何引用都会自动转换为指针值。


-5

结构默认情况下具有公开的数据成员,因此在struct的情况下可以访问main中的数据,而在class的情况下则不能。因此,结构包装是有效的。


1
您是否看到有关C的问题?在C中,没有public/private区别,也没有classes。问题是,为什么structC中需要a才能返回数组的值。
PJTraill '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.