C에서 구조체를 선언하지 않고 멤버의 배열크기를 알아내고 싶습니다.

raidol의 이미지

안녕하세요,

struct TEST{
int code;
char result[128];
int* err;
};

예를들어 위와같은 구조체 TEST가 있는데요.,
여기서 result 멤버의 sizeof 결과를 가져오고 싶습니다.

struct TEST test; 선언하고 sizeof(test.result); 하면 쉽겠지만,
선언하지 않고 가져올 수 있는 방법 없을까요? sizeof((struct TEST).result); 이건 뭐 당연히 안될테고..

방법이 없다면 임시변수 선언을 할 수밖에 없지만 방법이 없는건지 제가 모르는건지..-_-a

HDNua의 이미지

1. offsetof 매크로를 이용합니다.

#include <stdio.h>
#include <stddef.h>
struct TEST {
    int code;
    char result[128];
    int *err;
};
int main(void) {
    // err의 오프셋(4+128)에서 result의 오프셋(4)의 차이가 result의 크기가 됩니다.
    size_t size = offsetof(struct TEST, err) - offsetof(struct TEST, result);
    printf("%u \n", size);
    return 0;
}

다만 이 경우 구조체의 패딩에 관한 문제가 있어서,
4바이트 경계로 패딩이 설정되어있으면 char 형식 멤버의 크기를 4바이트로 뱉을 수 있다는 점 때문에
그렇게 신뢰할 방법은 아닙니다.

2. 구조체의 전체 크기에서 나머지 두 멤버의 크기를 뺍니다.

#include <stdio.h>
 
struct TEST {
    int code;
    char result[128];
    int *err;
} tmp;
 
int main(void) {
    size_t size = sizeof(struct TEST) - sizeof(int) - sizeof(int *);
    printf("%u \n", size);
    return 0;
}

이 또한 패딩 문제가 해결된 것이 아니기 때문에 신뢰할 수 없습니다.

3. result 멤버의 크기를 #define을 이용하여 정의하고 계산한 값을 반환합니다.

#include <stdio.h>
 
#define RESULT_CNT 128
struct TEST {
    int code;
    char result[RESULT_CNT];
    int *err;
};
 
int main(void) {
    // (총 변수의 개수 * 각 변수의 크기 = 총 변수의 크기)입니다.
    size_t size = RESULT_CNT * sizeof(char);
    printf("%u \n", size);
    return 0;
}

이해하기 쉽고 언제나 타당합니다.

L. 그냥 임시 변수를 만들어서 씁니다.

#include <stdio.h>
 
struct TEST {
    int code;
    char result[128];
    int *err;
} tmp;
 
int main(void) {
    size_t size = sizeof tmp.result;
    printf("%u \n", size);
    return 0;
}

당연히 언제나 타당합니다.

-----

The C Programming Language는 sizeof 연산자 뒤에 가능한 요소가 다음의 두 가지밖에 없다고 설명하고 있습니다. (번역본 p.330)
sizeof unary-expression
sizeof ( type-name )

즉 sizeof를 사용하려면 형식 이름이나 단항식만 가능한데 구조체의 멤버 이름은 형식 이름은 아니고,
구조체 변수를 정의하지 않은 상태에서 멤버 이름으로만 단항식을 구성할 수도 없으니 별도의 방법을 써야 합니다.

컴파일러가 확장해서 지원하지 않는 한, 문법적으로 이걸 지원하는 키워드는 없다는 것이 제 결론입니다.

저는 이렇게 생각했습니다.

klyx의 이미지

sizeof((struct TEST*)NULL)->result) 또는 sizeof(((struct TEST){}).result) 하면 됩니다.
전자는 NULL 포인터를 디레퍼런싱하지만 sizeof는 compile 타임에 평가되므로 실제로 실행되는 식이 아니기 때문에 실행시에 죽는 일은 없습니다.
NULL이라는 값을 썼지만 실제로 실행되지 않기 때문에 아무 정수나 와도 상관없습니다.
후자는 인스턴스를 생성하는 식이지만 마찬가지로 실제로 실행되는 식이 아니므로 실제로 객체를 만들지는 않습니다.

HDNua의 이미지

1. sizeof (((struct TEST *)NULL)->result);와 같이 쓸 수 있다는 생각은 못 했네요. 놀랐습니다.

2. 테스트를 위해 다음과 같이 코드를 작성해보았습니다.

#include <stdio.h>
 
struct TEST {
    int code;
    char result[128];
    int *err;
};
 
int main(void) {
    size_t size1 = 0, size2 = 0;
 
    size1 = sizeof (((struct TEST*)NULL)->result);
    size2 = sizeof (((struct TEST){}).result);
 
    printf("%u %u \n", size1, size2);
 
    return 0;
}

다른 온라인 컴파일러에서는 모두 정상적으로 동작하는 반면, Visual Studio에서 빌드한 결과, size1에는 이상이 없지만 size2의 경우 C2059 구문 오류를 뱉으며 빌드에 실패했습니다.

두 번째 구문은 표준에 의하면 언제나 타당한 구문인가요?
그러니까, 이 경우는 Visual Studio가 C 컴파일러 구현을 온전히 하지 못한 것일까요?

저는 이렇게 생각했습니다.

klyx의 이미지

compound literal이라고 C99에서 추가된 문법입니다. msvc의 지원이 어떤지는 모르겠네요.

HDNua의 이미지

입문서랑 TCPL만으로 공부했더니 바뀐 C 문법은 제가 정말 모르는군요.
C99도 새롭게 공부해봐야겠습니다.

저는 이렇게 생각했습니다.

raidol의 이미지

답변주신 두분께 감사드립니다. 방금 컴파일 해봤는데 잘됩니다.^^

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.