처음보는 union 초기화 방법

vani2의 이미지

union TestUni {
	int a, b, c;
	double a2, b2, c2;
	};
 
int main(int argc,char *argv[]) {
	TestUni test = {test.b = 23};
	cout<<test.b<<endl;
	return 0;
	}

이런 이상한 초기화 기법을 보았는데 이게 무엇인가요?

chanik의 이미지

"union initialization"으로 구글을 검색해보니 여러 가지가 자료가 나오네요.

Designated initializer 라고 부르는 모양입니다.

- http://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html
- http://stackoverflow.com/questions/7008784/how-to-initialize-a-union-object

C99에서 새로 지원되는 기능이고,
과거 C89에서 아래와 같이 union 정의와 초기화를 따로 하던 것을 한 번에 할 수 있게 되었네요.

union TestUni test;
test.b = 23;
klyx의 이미지

designated initializer는 공용체/구조체/배열의 변수명을 적지 않습니다. 그리고 C++에는 해당되지 않는 내용입니다.

chanik의 이미지

결론: 말씀하신 바가 맞는 것 같고, 코딩할때도 그런 원칙을 따르는 것이 좋을 것입니다.

----

다만 컴파일러에 따라서는 엄밀히 표준대로 행동하기도 하고 좀 느슨하게 행동하기도 합니다.
저는 gcc/g++ 4.1.2와 4.4.7을 가지고 몇 가지 실험해보고 댓글을 달았던 것인데,
gcc/g++에서는 좀 느슨하게 처리되더군요.

우선 gcc로 컴파일할 때는 union 이름(test.)을 빼야 맞겠지만, 지정하더라도 컴파일러가 받아줍니다.
(컴파일시 gcc extension을 끄도록 -ansi (== -std=c89) 또는 -std=c99 옵션을 줘봐도 결과는 마찬가지였습니다)

    /* TestUni test = {test.b = 23}; */          <-- 오류발생
    union TestUni test2 = {test2.b = 23};        <-- OK (GCC는 허용)
    union TestUni test3 = { .b = 23 };           <-- OK (표준)

g++로 컴파일할 때는 C++에 이런 문법이 없으니 그냥 오류가 나야 맞지만
아래와 같이 test.b 식으로 union 이름을 적어주면 컴파일이 되더군요.
( 역시 g++ extention을 끄도록 -ansi (== -std=c++98) 옵션을 줘도 마찬가지임 )

    TestUni test = {test.b = 23};                <-- OK
    union TestUni test2 = {test2.b = 23};        <-- OK
    /* union TestUni test3 = { .b = 23 }; */     <-- 오류발생

이렇게 특정 컴파일러가 허용하더라도
코딩시에는 C++이 아닌 C에서만 사용하고, 표준대로 union 이름은 넣지 말고 쓰는 것이 좋겠죠.

최초 질문자인 plusb님은 아마도 위의 g++ 컴파일을 해 보고 질문하신 것 같은데,
g++이 허용해준 위 문법을 저는 그냥 designated initializer라고 답변하고
C99에서 정의된 것이라고 얼버무린 것이었습니다.

klyx의 이미지

문제는 이게 전혀 designated initializer처럼 행동하지 않는다는 겁니다.
저도 처음 보는거라 몇가지 테스트해봤는데, 시험 삼아 다음 코드를 돌려보세요.

#include <iostream>
struct Test { int a, b; };
int main() {
   Test t = { t.b = 1, t.a = 0 };
   std::cout << t.a << t.b << std::endl;
   return 0;
}
정말 C99의 designated initializer를 확장시킨 표현이라면 출력 결과는 01이 나와야 하지만, 00이 출력됩니다.
저도 이런 구문은 본적이 없어서 표준에서 보장하는 적법한 구문인지 GCC의 확장인지 또는 버그인지 모르겠습니다.
다만 이로부터 유추해보면 결국 (적어도 GCC에서 이 구문에 대해서) {}는 평범한 initializer-list처럼 작동하며, t.b=1은 a를 초기화하는 구문이되고, t.a=0은 b를 초기화하는 구문이 되며, 마지막에 t.a=0으로 a를 덮어씌우면서 그 값으로 b를 초기화하기 때문에 둘다 0이되는 걸로 보입니다.
chanik의 이미지

union에 대해 생각할 때는 별 문제를 못 느꼈는데,
struct에 해 보니 말씀하신대로 정말 다른 점이 있네요.

C99를 지원하는 gcc를 이용해서 C 컴파일을 해봤습니다.
표준대로 struct 변수명을 주지 않고 초기화하면 각 멤버 지정순서와 무관하게 일관적인 결과가 나오지만
struct 변수명을 주게 되면 기대와는 다른 엉뚱한 결과가 나오네요.

#include <stdio.h>
struct Test { int a, b; };
int main() {
    struct Test t1 = {   .a = 1,   .b = 3 };
    struct Test t2 = {   .b = 1,   .a = 3 };
    struct Test t3 = { t3.a = 1, t3.b = 3 };
    struct Test t4 = { t4.b = 1, t4.a = 3 };
 
    printf("%d%d\n",  t1.a, t1.b);
    printf("%d%d\n",  t2.a, t2.b);
    printf("%d%d\n",  t3.a, t3.b);
    printf("%d%d\n",  t4.a, t4.b);
    return 0;
}
 
# 실행결과
13
31
13
13

struct 변수명을 주는 (비표준) 초기화방식은 C/C++ 막론하고 어디에서도 쓰지 말고,
표준대로 struct 변수명 없이 쓰고, C 코딩시에만 써야겠군요.

날카로운 지적 감사합니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.