结构体有啥特别之处?

Posted

技术标签:

【中文标题】结构体有啥特别之处?【英文标题】:What is special about structs?结构体有什么特别之处? 【发布时间】:2016-08-20 17:06:21 【问题描述】:

我知道在 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;

【问题讨论】:

你可以用union 做同样的事情。工会有什么特别之处? 你应该问为什么数组在 C 中如此奇怪。 当返回一个结构时,如果结构不适合几个寄存器,那么编译器分配的“隐藏”内存,结构被复制(通过 memcpy())到隐藏然后将内存再次复制(通过 memcpy())到调用者的结构变量。所有其他功能都丢失了“隐藏”的记忆。对memcpy() 的两次额外调用和“隐藏”内存的丢失是结构不应为passed toreturned from 函数的主要原因。最好的策略是传递一个指向结构的指针。 三个答案都没有解决结构的传递问题(而是他们只讨论传递数组),但他们没有回答这个问题。 @user3629249 - 不可能回答这个问题,因为这个问题的前提是缺乏理解。回答这个问题的唯一方法是尝试解释为什么不能问这个问题。想象一下,如果我问你“为什么蓝色和红色的颜色相同?”你会很快解释为什么你不能回答这个问题。 【参考方案1】:

问同样问题的更好方法是“数组有什么特别之处”,因为它是附加了特殊处理的数组,而不是structs。

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

【讨论】:

确实会造成很多混乱。 'x' 和 '&x' 是相同的值/地址有点疯狂。 newbs 间接错误并不奇怪:( 我的记忆可能在欺骗我,但不是有时间无法通过值传递structs 吗? @alk 我认为,当结构首次添加到语言中时,最初对将它们传递给函数/从函数返回它们有一些限制,但这些被明确标记为编译器中的缺陷很快就得到了纠正,这并不表明想要通过并返回它们有什么问题。 @jamesqf:struct Point short x, y, z;;。您真的想使用指针来移动它们吗?这样肯定不会节省空间。 @jamesqf 我不确定这是否值得回应。如果您认为 C 不只是汇编,如果您认为没有理由不使用指针,我可能会看到您可能认为传递结构是无用的。但是对于我们其他人来说,他们将 C 视为一种高级语言(尽管是低级语言,就像 HLL 一样),并且将 C 的类型系统视为通用的(除了数组的二等状态之外) ),为什么不想我们想要传递或返回结构? (顺便说一句,IIRC,K&R1 说结构传递正在进行中,并且在本书出版时它已在 V7 cc 中工作。)【参考方案2】:

首先,引用C11,第 §6.8.6.4 章,return 声明,(强调我的

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

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

另一方面,如果你返回一个数组,通过使用return &lt;array_name&gt;,它本质上返回数组的第一个元素的地址注意,如果数组是被调用函数的本地数组,则在调用者中无效。所以,以这种方式返回数组是不可能的。

所以,TL;DRstructs 没有什么特殊,特殊之处在于数组


注意:

再次引用C11,第 §6.3.2.1 章,(我的重点

除非它是sizeof 运算符、_Alignof 运算符或 一元 &amp; 运算符,或者是用于初始化数组的字符串文字,具有 type ''array of type'' 被转换为一个类型为 ''pointer to type'' 的表达式,它指向 到数组对象的初始元素,并且不是左值。 [...]

【讨论】:

OTOH 到底是什么?! @Sukl 这是“另一方面”的缩写 :) @Sukl 我认为这些缩写词大致与 Internet 本身一样古老。它们在 Usenet 的辉煌时期肯定被大量使用,并且在大多数论坛中仍然存在。值得庆幸的是,即使是不知情的人,Google 也可以对其进行解码 ;-) 而且只有少数今天经常使用(最常见的) @chi 是的。Google 非常出色,能够解码它们。 @Sukl:您可能会发现AcronymFinder 对追踪首字母缩略词很有用。【参考方案3】:

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

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

struct foo  ... ;

struct foo func( void )

  struct foo someFoo;
  ...
  return someFoo;

表达式someFoo 求值为struct foo 对象的;对象的内容从函数返回(即使这些内容包含数组)。

数组表达式的处理方式不同;如果它不是 sizeof 或一元 &amp; 运算符的操作数,或者如果它不是用于在声明中初始化另一个数组的字符串文字,则表达式从类型“array of T”到“指向T”的指针,表达式的值是第一个元素的地址。

所以你不能从函数返回一个数组按值,因为对数组表达式的任何引用都会自动转换为指针值。

【讨论】:

【参考方案4】:

默认情况下,结构具有公共数据成员,因此在结构的情况下可以访问 main 中的数据,但不能在类的情况下访问。所以,struct wrapping 是有效的。

【讨论】:

你看到问题是关于 C 的吗?在C中,没有public/private的区别,也没有classes。问题是为什么在 C 中需要 struct 来返回数组的值。

以上是关于结构体有啥特别之处?的主要内容,如果未能解决你的问题,请参考以下文章

C语言结构体中struct和typedef struct有啥区别?

golang快速入门数据类型特别之处(下)

typedef struct与struct定义结构体

Swift 中的类与结构体

谈谈结构体

Swift之深入解析类和结构体的本质