web-dev-qa-db-ja.com

構造体の特別な点は何ですか?

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;
}
81
user5619103

同じ質問をするより良い方法は、「配列の特別な点」です。なぜなら、structsではなく、特別な処理が付加された配列だからです。

ポインターによる配列の受け渡しの動作は、Cの元の実装にまでさかのぼります。配列はポインターに「減衰」し、特に言語に不慣れな人々の間でかなりの混乱を引き起こします。一方、構造体は、ints、doublesなどの組み込み型のように動作します。これには、 を除く、structに埋め込まれた配列が含まれます。 柔軟な配列メンバー 、コピーされません。

100
dasblinkenlight

まず最初に、C11、§6.8.6.4、returnステートメント、(emphasis mine

式を含むreturnステートメントが実行されると、式の値が返されますが関数呼び出し式の値として呼び出し元に返されます。

構造変数valueが返されるため、構造変数を返すことは可能です(そして正しい)。これは、プリミティブデータ型を返すことに似ています(たとえば、intを返す)。

一方、arrayを返す場合は、return <array_name>、基本的に配列の最初の要素のアドレスを返します注意、配列が呼び出された関数に対してローカルである場合、呼び出し側で無効になります。そのため、そのように配列を返すことはできません。

したがって、TL; DR、何もありませんspecial with structs、専門はarraysにあります。


注意:

引用符C11もう一度、§6.3.2.1、(私の強調

sizeof演算子のオペランドである場合を除き、_Alignof演算子、または単項&演算子、または配列の初期化に使用される文字列リテラル、型を持つ式''型の配列 ''は、型'を持つ式に変換されます「型へのポインター」配列オブジェクトの初期要素を指しますであり、左辺値ではありません。 [...]

38
Sourav Ghosh

struct型について特別なことはありません。 array型には特別なものがあり、関数から直接返されるのを防ぎます。

struct式は、他の非配列型の式と同様に扱われます。 structの-​​に評価されます。だからあなたのようなことをすることができます

struct foo { ... };

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

someFooは、struct fooオブジェクトのに評価されます。オブジェクトのコンテンツが関数から返されます(それらのコンテンツに配列が含まれている場合でも)。

配列式の扱いは異なります。 sizeof演算子または単項&演算子のオペランドではない場合、または宣言内の別の配列を初期化するために使用される文字列リテラルでない場合、式は「Tの配列」を「Tへのポインター」と入力すると、式の値は最初の要素のアドレスになります。

したがって、配列式への参照は自動的にポインター値に変換されるため、関数から配列値によるを返すことはできません。

11
John Bode