컴공과 대학생 질문드립니다) C99 컴파일 관련

0Hooo@Naver의 이미지

안녕하세요! 저는 고려대학교 편입을 준비하고 있는 학생입니다.

다름이 아니라 C99의 배열에 대해 공부하고 있던 와중 궁금한 점이 생겨 질문 드립니다.

1. 초기값 리스트의 크기가 배열의 크기보다 큰 경우 에러가 발생한다.

2. 가변길이배열(VLA)라도 sizeof연산은 컴파일 시점에 수행된다.

이 두 선지중 1번이 틀리고 2번이 맞다고 하는데요,

강의하시는 분 설명은 이렇습니다.

C99 의 IDE에서는 초기값 리스트의 크기가 배열의 크기보다 큰 경우에도 에러를 내어주지 않는다고 하고,
Visual Studio에서 에러가 나는 이유는 컴파일러 자체가 걸러주기 때문이라고 설명하십니다.

2번째 선지가 맞는 이유는 그냥 특이사항으로 외우라고 하시는데, 외국 글이나 다른 인터넷에 찾아보아도
sizeof 연산은 runtime에 수행된다고 나와있는 것 같습니다..

정확한 정보인지 모르겠어서 질문드립니다.

참고로 강의를 찍으시는 분은 현직 개발자십니다..

ymir의 이미지

1 - 대개는 compiler 가 실행 옵션에 따라 warning 이나 error 를 띄워주는데, 운이 좋다면(?) run time 에 문제가 드러나겠죠. 표준에 array 에 initializer 를 assign 하는 경우, 크기에 대한 언급이 있었는지는 잘 모르겠네요.

2 - sizeof 는 compile time 에 integer constant 로 변환되는데, VLA 의 경우에는 run time 에 평가됩니다. 내용이 뭔가 반대로 된 것 같네요.

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
6.5.3.4 The sizeof operator
- 2, 7 항목 참조

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

나빌레라의 이미지

해보면 되겠쥬?

#include <stdio.h>

int main(int argc, char* argv[])
{
    int a[3] = {1,2,3,4,5};
    for (int i = 0 ; i < 3 ; i++) {
        printf("%d\n", a[i]);
    }
    return 0;
}

컴파일 하면

cc     bigger_array_init.c   -o bigger_array_init
bigger_array_init.c: In function ‘main’:
bigger_array_init.c:5:27: warning: excess elements in array initializer
    5 |         int a[3] = {1,2,3,4,5};
      |                           ^
bigger_array_init.c:5:27: note: (near initialization for ‘a’)
bigger_array_init.c:5:29: warning: excess elements in array initializer
    5 |         int a[3] = {1,2,3,4,5};
      |                             ^
bigger_array_init.c:5:29: note: (near initialization for ‘a’)

gcc는 에러는 아니고 워닝이네요.

코드를 요래 수정 하면

for (int i = 0 ; i < 5 ; i++) {

결과는

1
2
3
311017216
1466569650

컴파일러가 알아서 배열 크기만큼만 짤라서 초기화하니깐 워닝으로도 충분한가봅니다.

int fsize3(int n)
{
    char b[n+3]; // variable length array
    return sizeof b; // execution time sizeof
}

요건 가변 배열에 대한 sizeof 함수고요

int fsize3(void)
{
    char b[23]; // variable length array
    return sizeof b; // execution time sizeof
}

요건 고정 배열에 대한 sizeof 함수입니다.

컴파일해서 역어셈블 해 보면

0000000000001169 <fsize3>:
    1169:   f3 0f 1e fa             endbr64
    116d:   55                      push   %rbp
    116e:   48 89 e5                mov    %rsp,%rbp
    1171:   48 83 ec 30             sub    $0x30,%rsp
    1175:   89 7d dc                mov    %edi,-0x24(%rbp)
    1178:   64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
    117f:   00 00 
    1181:   48 89 45 f8             mov    %rax,-0x8(%rbp)
    1185:   31 c0                   xor    %eax,%eax
    1187:   48 89 e0                mov    %rsp,%rax
    118a:   48 89 c7                mov    %rax,%rdi
    118d:   8b 45 dc                mov    -0x24(%rbp),%eax
    1190:   8d 48 03                lea    0x3(%rax),%ecx
    1193:   48 63 c1                movslq %ecx,%rax
    1196:   48 83 e8 01             sub    $0x1,%rax
    119a:   48 89 45 e8             mov    %rax,-0x18(%rbp)
    119e:   48 63 c1                movslq %ecx,%rax
    11a1:   ba 10 00 00 00          mov    $0x10,%edx
    11a6:   48 83 ea 01             sub    $0x1,%rdx
    11aa:   48 01 d0                add    %rdx,%rax
    11ad:   be 10 00 00 00          mov    $0x10,%esi
    11b2:   ba 00 00 00 00          mov    $0x0,%edx
    11b7:   48 f7 f6                div    %rsi
    11ba:   48 6b c0 10             imul   $0x10,%rax,%rax
    11be:   48 89 c6                mov    %rax,%rsi
    11c1:   48 81 e6 00 f0 ff ff    and    $0xfffffffffffff000,%rsi
    11c8:   48 89 e2                mov    %rsp,%rdx
    11cb:   48 29 f2                sub    %rsi,%rdx
    11ce:   48 39 d4                cmp    %rdx,%rsp
    11d1:   74 12                   je     11e5 <fsize3+0x7c>
    11d3:   48 81 ec 00 10 00 00    sub    $0x1000,%rsp
    11da:   48 83 8c 24 f8 0f 00    orq    $0x0,0xff8(%rsp)
    11e1:   00 00 
    11e3:   eb e9                   jmp    11ce <fsize3+0x65>
    11e5:   48 89 c2                mov    %rax,%rdx
    11e8:   81 e2 ff 0f 00 00       and    $0xfff,%edx
    11ee:   48 29 d4                sub    %rdx,%rsp
    11f1:   48 89 c2                mov    %rax,%rdx
    11f4:   81 e2 ff 0f 00 00       and    $0xfff,%edx
    11fa:   48 85 d2                test   %rdx,%rdx
    11fd:   74 10                   je     120f <fsize3+0xa6>
    11ff:   25 ff 0f 00 00          and    $0xfff,%eax
    1204:   48 83 e8 08             sub    $0x8,%rax
    1208:   48 01 e0                add    %rsp,%rax
    120b:   48 83 08 00             orq    $0x0,(%rax)
    120f:   48 89 e0                mov    %rsp,%rax
    1212:   48 83 c0 00             add    $0x0,%rax
    1216:   48 89 45 f0             mov    %rax,-0x10(%rbp)
    121a:   48 89 fc                mov    %rdi,%rsp
    121d:   89 c8                   mov    %ecx,%eax
    121f:   48 8b 55 f8             mov    -0x8(%rbp),%rdx
    1223:   64 48 2b 14 25 28 00    sub    %fs:0x28,%rdx
    122a:   00 00 
    122c:   74 05                   je     1233 <fsize3+0xca>
    122e:   e8 2d fe ff ff          call   1060 <__stack_chk_fail@plt>
    1233:   c9                      leave
    1234:   c3                      ret

졸라 길죠? 누가 봐도 run time에 뭘 하고 있는 코드입니다.

그러면 고정 배열일 때는?

0000000000001169 <fsize3>:
    1169:   f3 0f 1e fa             endbr64
    116d:   55                      push   %rbp
    116e:   48 89 e5                mov    %rsp,%rbp
    1171:   48 83 ec 20             sub    $0x20,%rsp
    1175:   64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
    117c:   00 00 
    117e:   48 89 45 f8             mov    %rax,-0x8(%rbp)
    1182:   31 c0                   xor    %eax,%eax
    1184:   b8 17 00 00 00          mov    $0x17,%eax
    1189:   48 8b 55 f8             mov    -0x8(%rbp),%rdx
    118d:   64 48 2b 14 25 28 00    sub    %fs:0x28,%rdx
    1194:   00 00 
    1196:   74 05                   je     119d <fsize3+0x34>
    1198:   e8 c3 fe ff ff          call   1060 <__stack_chk_fail@plt>
    119d:   c9                      leave
    119e:   c3                      ret

짧쥬? 중간에 0x17을 eax에 넣는 코드가 보입니다. 0x17은 23이니깐 컴파일 타임에 int로 변환하는거 맞네요.

----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라

awidesky의 이미지

IDE가 아니라 표준을 봐야지요..
특히 C/C++과 같은 언어는 컴파일러 한두개의 behavior가 아니라 정확한 표준을 참고해야 합니다.
C99 표준 §6.7.8.2
"No initializer shall attempt to provide a value for an object not contained within the entity being initialized."

§6.5.3.4
"2. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant."

댓글 달기

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