结构体有啥特别之处?
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 to
或returned from
函数的主要原因。最好的策略是传递一个指向结构的指针。
三个答案都没有解决结构的传递问题(而是他们只讨论传递数组),但他们没有回答这个问题。
@user3629249 - 不可能回答这个问题,因为这个问题的前提是缺乏理解。回答这个问题的唯一方法是尝试解释为什么不能问这个问题。想象一下,如果我问你“为什么蓝色和红色的颜色相同?”你会很快解释为什么你不能回答这个问题。
【参考方案1】:
问同样问题的更好方法是“数组有什么特别之处”,因为它是附加了特殊处理的数组,而不是struct
s。
通过指针传递和返回数组的行为可以追溯到 C 的原始实现。数组“衰减”为指针,引起了很多混乱,尤其是在刚接触该语言的人中。另一方面,结构的行为就像内置类型,例如int
s、double
s 等。这包括嵌入在struct
中的任何数组,除了flexible array members,它们不会被复制.
【讨论】:
确实会造成很多混乱。 'x' 和 '&x' 是相同的值/地址有点疯狂。 newbs 间接错误并不奇怪:( 我的记忆可能在欺骗我,但不是有时间无法通过值传递struct
s 吗?
@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 <array_name>
,它本质上返回数组的第一个元素的地址注意,如果数组是被调用函数的本地数组,则在调用者中无效。所以,以这种方式返回数组是不可能的。
所以,TL;DR,struct
s 没有什么特殊,特殊之处在于数组。
注意:
再次引用C11
,第 §6.3.2.1 章,(我的重点)
除非它是
sizeof
运算符、_Alignof
运算符或 一元&
运算符,或者是用于初始化数组的字符串文字,具有 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
或一元 &
运算符的操作数,或者如果它不是用于在声明中初始化另一个数组的字符串文字,则表达式从类型“array of T
”到“指向T
”的指针,表达式的值是第一个元素的地址。
所以你不能从函数返回一个数组按值,因为对数组表达式的任何引用都会自动转换为指针值。
【讨论】:
【参考方案4】:默认情况下,结构具有公共数据成员,因此在结构的情况下可以访问 main 中的数据,但不能在类的情况下访问。所以,struct wrapping 是有效的。
【讨论】:
你看到问题是关于 C 的吗?在C中,没有public
/private
的区别,也没有class
es。问题是为什么在 C 中需要 struct
来返回数组的值。以上是关于结构体有啥特别之处?的主要内容,如果未能解决你的问题,请参考以下文章