2015-01-09 7 views
31

: 우리는 익명의 struct 반환 foo라는 이름의 함수를 정의하는 것처럼C에서 익명 구조체를 반환하는 방법은 무엇입니까? 나는 다음과 같은 코드는 컴파일 것을 깨달았다 몇 가지 코드를 시도

struct { int x, y; } foo(void) { 
} 

것 같다.

내 질문은 : 그것은 단지 내 컴파일러로 컴파일 할 수 있습니까 아니면이 합법적 인 C (99)입니까? 그렇다면 return 문에 대한 올바른 구문은 무엇이며 어떻게 반환 된 값을 변수에 올바르게 할당 할 수 있습니까?

+0

는 것 같다가 오류를주고 엄격한 gcc.With C99의 일부 해킹 http://ideone.com/665vM2 – Ankur

+4

@Shan : 함수 정의 구문은 여전히 ​​유효합니다. 단순히 누락 된 return 문에 대해 불만을 토로합니다 (이 상황에서 올바른 return 문을 수행하는 방법은 묻습니다). – Askaga

+0

C99에는 익명 구조체와 같은 것이 없습니다. _compound 리터럴 _을 만들 수는 있지만 항상 로컬 범위가 있습니다. – Lundin

답변

23

반환 할 구조체는 익명 구조체가 아닙니다. C 표준은 익명 구조체를 태그를 사용하지 않는 다른 구조체의 멤버로 정의합니다. 반환하는 것은 태그가없는 구조체이지만 멤버가 아니기 때문에 익명이 아닙니다. Gcc는 이름이 < 익명>을 사용하여 태그가없는 구조체를 나타냅니다.

함수에서 동일한 구조체를 선언하려고한다고 가정 해 보겠습니다.

struct { int x, y; } foo(void) 
{ 
    return (struct { int x, y; }){ 0 } ; 
} 

GCC는 그것에 대해 불평 : 호환되지 않는 유형의 유형을 반환 '> < 익명 구조체'하지만 '구조체는 < 익명>은'

이 분명히 종류가 호환되지 않습니다 예상했다.

6.2.7 지원되는 유형과 복합 형이

1 : 자신의 종류가 같은 경우 두 가지 유형이 호환되는 유형이 표준에서 보면 우리는 것을 알 수있다. 두 유형이 호환되는지 여부를 판별하기위한 추가 규칙은 유형 지정자의 경우 6.7.2, 유형 규정 자의 경우 6.7.3, 선언자의 경우 6.7.6에 설명되어 있습니다. 또한 별도의 번역본 인 단위로 선언 된 두 개의 구조체, 공용체 또는 열거 형은 해당 태그와 멤버가 다음 요구 사항을 충족시키는 경우 호환됩니다. 태그로 선언 된 경우 다른 태그와 동일한 태그로 선언해야합니다.두 번역 단위 모두 해당 번역 단위 내에서 완성 된 경우 다음 추가 요구 사항이에 적용됩니다. 해당 구성원의 각 쌍이 호환 가능한 형식으로 선언되도록 해당 구성원간에 일대일 대응이 있어야합니다. 한 쌍의 멤버가 정렬 지정자로 선언되면 다른 멤버는 동등한 정렬 지정자로 선언됩니다. 한 쌍의 멤버가 이름으로 선언되면 다른 멤버는 같은 이름으로 선언됩니다. 두 구조체의 경우, 대응하는 멤버는 같은 순서로 선언되어야한다. 2 개의 구조체 또는 공용체의 경우, 대응하는 비트 필드는 같은 폭을 가져야한다. 2 개의 열거 형의 경우, 대응하는 멤버는 같은 값을 가져야한다.

두 번째 굵은 부분은 구조체에 태그가없는 경우 (예 :이 예와 같이) 해당 부분에 나열된 추가 요구 사항을 따라야한다고 설명합니다. 그러나 첫 번째 굵은 글씨 부분을 별도의 번역 단위로 사용해야 할 경우이 예제의 구조체는 그렇지 않습니다. 그래서 그들은 호환되지 않으며 코드는 유효하지 않습니다.

:

당신이 구조체를 선언하고이 함수를 사용하는 경우, 당신은 두 구조체가 같은 태그가 있어야이 규칙을 위반하는 태그를 사용할 필요가 있기 때문에 코드가 정확한지 확인하는 것은 불가능합니다

struct t { int x, y; } ; 

struct { int x, y; } foo(void) 
{ 
    struct t var = { 0 } ; 

return var ; 
} 

다시 한번의 GCC는 불평 : 호환되지 않는 유형의 유형 '구조체 t'만 반환 할 때 '구조체를 < 익명>'

+0

흠, 재미있는 전에는 표준의 그 부분을 읽지 못했습니다. "두 종류의 유형이 서로 호환되면 호환 유형이 있습니다."라는 말은 내게 완전한 말도 안되는 것처럼 보입니다 (이 상황에 적용될 수도 있고, 누가 알 수도 있습니다). 귀하의 예제에서 두 가지 유형이 호환되지 않지만 둘 다 ** 다른 번역 단위에서 정의 된 유사한 유형과 호환 될 수 있다고 결론을 내릴 수 있습니까? 따라서 호환성은 전이 관계가 아닙니다. –

+0

@MarcvanLeeuwen 유형은 동일해야하며 많은 예외가 있습니다. 태그가없는 구조체는 다른 번역 단위에서 정의 된 경우 호환 될 수 있습니다. – 2501

8

당신은 아마 할 수 없습니다 명시 적으로return 함수에서 일부 총액 (당신은 결과의 유형을 얻을 수있는 typeof 확장자를 사용하지 않는 한). 이야기의

도덕적 당신이 반환하는 함수를 선언 할 경우에도 익명struct 당신이 실질적으로 그렇게해서는 안 것입니다.

struct twoints_st { int x; int y; }; 
struct twoints_st foo (void) { 
    return ((struct twoints_st) {2, 3}); 
}; 

이 구문 괜찮다는 것을 알 수 있지만, 실행시 일반적으로 정의되지 않은 동작이, (예를 들어, 당신이 그것을 내부 exit를 부를 수) return없이 기능을 가지고 :

는 대신, struct 코드의 이름을 지정합니다. 하지만 왜 (아마도 합법적 인) 코드를 작성 하시겠습니까?

struct { int xx; int yy; } bizarrefoo(void) { exit(EXIT_FAILURE); } 
12

예상이 GCC의 내 버전에서 작동하지만 전체 해킹처럼 보인다. 아마도 고유 한 구조 태그를 생성하는 추가 복잡성을 처리하고 싶지 않은 자동 생성 코드에서 유용 할 수 있습니다. 그러나 그 합리화조차도 예상 할 수 있습니다.

struct { int x,y; } 
foo(void) { 
    typeof(foo()) ret; 
    ret.x = 1; 
    ret.y = 10; 
    return ret; 
} 

main() 
{ 
    typeof(foo()) A; 

    A = foo(); 

    printf("%d %d\n", A.x, A.y); 
} 

또한, 컴파일러에 존재() 대해서 typeof에 따라입니다 - GCC와 LLVM은 그것을 지원하는 것,하지만 확실히 많은 컴파일러하지 않습니다입니다.

+1

이 기술은 생각보다 합리적 일 수 있습니다. D 언어가 어떻게 편리한 문법을 ​​가지고 있는지 보시오 : [https://dpaste.dzfl.pl/c5880e348812](https://dpaste.dzfl.pl/c5880e348812) – Cauterite

1

이것은 GCC의 최신 버전까지 작동합니다. 특히 매크로가있는 동적 배열을 만드는 데 유용합니다. 예를 들어 :

#define ARRAY_DECL(name, type) struct { int count; type *array; } name 

그런 다음 당신은 당신은 어떤 유형의 동적 배열을 만들 수 있기 때문에 유용 등, realloc을 사용하여 배열을 만들 수 있고, 그들 모두를 할 수있는 한 가지 방법이있다. 그렇지 않으면 결국 void *을 많이 사용하게되고 실제로 캐스트를 사용하여 값을 다시 가져 오는 함수를 작성하게됩니다. 이 모든 것을 매크로로 단축 할 수 있습니다. 그것은 그들의 아름다움입니다.

0

또는 당신은 무한 재귀 만들 수 있습니다 : 나는 완전히 합법적 인 생각

struct { int x, y; } foo(void) { 
    return foo(); 
} 

합니다.

+0

구조체 타입에 대한 포인터를 반환하는 것은 어떻습니까? 첫 번째 호출에서 일부 메모리를 malloc하고 전역 void *에 포인터를 저장합니다. 그 후에 전역 void *를 리턴하면됩니다. 나는 그 사람이 실제로 선언 한 유형 1을 사용할 수 있다고 생각합니다. – supercat

0

내가 발견 한 해킹없이 C++ 14에서 익명 구조체를 반환하는 방법이 있습니다.
함수 내 경우
은 매우 설명하지 intersect() 반환 std::pair<bool, Point> 그래서는 결과에 대한 사용자 정의 유형을하기로 결정 (C++ 11 나는 가정, 충분합니다).
별도의 struct을 만들 수 있었지만이 특별한 경우에만 필요하기 때문에 가치가 없었습니다. 그래서 익명의 구조체를 사용했습니다.

auto intersect(...params...) { 
    struct 
    { 
     Point point; 
     bool intersects = false; 
    } result; 

    // do stuff... 

    return result; 
} 

그리고 지금은, 대신에 추한

if (intersection_result.first) { 
    Point p = intersection_result.second 

의 내가 찾고 훨씬 더를 사용할 수 있습니다

if (intersection_result.intersects) { 
    Point p = intersection_result.point; 
+0

질문은 C가 아니라 C++입니다. – Ruslan