구조체의 특별한 점은 무엇입니까?


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

19
오히려 C에서 배열이 왜 그렇게 이상한지 물어봐야합니다.
CodesInChaos

구조체를 반환 할 때 구조체가 두 개의 레지스터에 맞지 않으면 컴파일러가 할당 한 '숨겨진'메모리, 구조체는 (memcpy ()를 통해) 숨겨진 메모리로 복사 된 다음 다시 (memcpy (를 통해) 복사됩니다. )) 호출자의 구조체 변수. 그 '숨겨진'메모리는 다른 모든 기능에 손실됩니다. 두 개의 추가 호출 memcpy()과 '숨겨진'메모리의 손실은 구조체가 함수 passed to도 아니 어야하는 주된 이유입니다 returned from. 가장 좋은 정책은 구조체에 대한 포인터를 전달하는 것입니다.
user3629249 apr

세 가지 답변 중 구조체 전달을 다루지는 않지만 (배열 전달 만 논의하는 대신) 질문에 대답하지 않습니다.
user3629249

1
@ user3629249-질문이 이해 부족을 전제로하기 때문에 질문에 대답 할 수 없습니다. 질문에 대답하는 유일한 방법은 질문을 할 수없는 이유를 설명하는 것입니다. "왜 파란색은 빨간색과 같은 색입니까?"라고 물었다 고 상상해보십시오. 질문에 답할 수없는 이유를 빠르게 설명 할 수 있습니다.
Hogan

답변:


100

동일한 질문을하는 더 좋은 방법은 "배열에 대해 특별한 점"이 될 것입니다 struct. s가 아니라 특수 처리가 연결된 배열이기 때문입니다 .

포인터로 배열을 전달하고 반환하는 동작은 C의 원래 구현으로 거슬러 올라갑니다. 배열은 포인터에 대해 "감쇠"하여 특히 언어를 처음 접하는 사람들 사이에서 많은 혼란을 야기합니다. 반면에 구조체는 ints, doubles 등과 같은 내장 유형처럼 작동합니다 . 여기에는 복사되지 않는 유연한 배열 멤버를struct 제외하고에 포함 된 모든 배열이 포함됩니다 .


4
실제로 '많은 혼란을 일으킨다'. 'x'와 '& x'가 같은 값 / 주소 인 것은 일종의 미친 짓입니다. newbs가 간접적으로 잘못되었다는 것은 놀라운 일이 아닙니다 :(
Martin James

1
내 기억이 속일 수 있지만 structs를 값으로 전달할 수 없었던 때가 없었습니까?
alk

5
@alk 처음에 구조체가 언어에 추가되었을 때 처음에는 함수로 전달 / 반환하는 데 몇 가지 제한이 있었지만 표시가 아니라 곧 수정 된 컴파일러 결함으로 분명히 표시되었습니다. 통과해서 돌려주고 싶은 게 잘못됐다고
Steve Summit

8
@jamesqf : struct Point {short x, y, z;};. 포인터를 사용하여 이동하고 싶습니까? 당신은 확실히 이런 식으로 공간을 절약하지 않습니다.
Mark VY

6
@jamesqf 이것이 응답 할 가치가 있는지 잘 모르겠습니다. C가 어셈블리에 지나지 않는다고 믿고 포인터를 사용하지 않을 이유가 없다고 믿는다면 구조체 전달이 쓸모 없다고 생각할 수 있습니다. 그러나 C를 높은 수준의 언어로 취급하고 (HLL이 진행하는 것처럼 낮은 수준의 언어 임에도 불구하고) C의 유형 시스템을 일반적으로 취급하는 나머지 사람들에게는 (배열의 2 등급 상태를 제외하고는 ), 왜 않을 것이다 우리는 통과 또는 구조체를 반환하려면? (BTW, IIRC, K & R1은 구조체 전달이 진행 중이며 책이 나왔을 때 V7 cc에서 작동했다고 말했습니다.)
Steve Summit

38

우선, 인용하다 C11 , §6.8.6.4 장, return성명 ( 내 강조 )

만약 return식이 문이 실행되면 의 값이 함수 호출 식의 값으로 호출자에게 반환 됩니다.

구조 이 반환 되기 때문에 구조 변수 반환이 가능하고 정확합니다 . 이는 모든 기본 데이터 유형을 반환하는 것과 유사합니다 ( int예 :를 반환 ).

반면 에를 사용하여 array 를 반환하면 return <array_name>기본적으로 배열 NOTE 의 첫 번째 요소 주소를 반환합니다.이 주소 는 배열이 호출 된 함수에 대해 로컬 인 경우 호출자에서 유효하지 않게됩니다. 따라서 이러한 방식으로 배열을 반환하는 것은 불가능합니다.

그래서, TL; DR은 , 아무것도가 특별struct의, 전문가에 배열 .


노트:

C11다시 인용 , §6.3.2.1 장 ( 내 강조점 )

그것의 오퍼랜드 인 경우를 제외하고 sizeof오퍼레이터의 _Alignof조작 또는 단항 &연산자, 또는 어레이를 초기화하는 데 사용되는 캐릭터 문자이다 형 갖는 식 '유형의 배열을' 유형의 표현으로 변환된다 ' 유형에 대한 포인터 '' 는 배열 객체의 초기 요소를 가리키며 lvalue가 아닙니다. [...]


OTOH는 정확히 무엇입니까?!

1
그것은 : "반면에"의 약어입니다 @Sukl
Sourav 고쉬

1
@Sukl 저는 이러한 약어가 인터넷 자체만큼이나 오래되었다고 생각합니다. 그들은 확실히 Usenet의 영광의 날 동안 많이 사용되었으며 여전히 대부분의 포럼에서 살아남습니다. 고맙게도, 알지 못하는 사람도 구글이 해독 할 수 있습니다 ;-) 그리고 오늘날 자주 사용되는 것은 몇 개뿐입니다 (가장 일반적인 것)
chi

@chi yes. Google은이를 해독 할 수있는 능력이 매우 뛰어납니다.

1
@Sukl : AcronymFinder가 약어를 추적하는 데 유용하다는 것을 알 수 있습니다 .
Jonathan Leffler

11

struct유형 에 대해 특별한 것은 없습니다 . 배열 유형 에 대해 함수에서 직접 반환되는 것을 방지하는 특별한 것이 있다는 것입니다.

struct발현 다른 배열이 아닌 형태의 식처럼 취급되고; 의 으로 평가됩니다 struct. 그래서 당신은 같은 일을 할 수 있습니다

struct foo { ... };

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

표현식 은 객체 someFoo 으로 평가됩니다 struct foo. 객체의 내용은 함수에서 반환됩니다 (해당 내용에 배열이 포함되어 있더라도).

배열 표현식은 다르게 처리됩니다. sizeof또는 단항 &연산자 의 피연산자 가 아니거나 선언에서 다른 배열을 초기화하는 데 사용되는 문자열 리터럴이 아닌 경우 식은 "array of T" 유형 에서 "pointer to"로 변환 ( "감쇠") 됩니다.T " . , 식의 값은 첫 번째 요소의 주소입니다.

따라서 배열 표현식에 대한 모든 참조는 자동으로 포인터 값으로 변환되기 때문에 함수에서 으로 배열 반환 할 수 없습니다 .


-5

구조체는 기본적으로 데이터 멤버를 public으로하므로 구조체의 경우 main의 데이터에 액세스 할 수 있지만 클래스의 경우에는 액세스 할 수 없습니다. 따라서 구조체 래핑이 유효합니다.


1
질문이 C에 관한 것임을 보셨습니까? C에서는 public/ private구별이없고 classes 가 없습니다 . 질문은 왜struct 배열의 값을 반환하기 위해 C에서 가 필요한 입니다.
PJTraill
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.