gdb로 배열의 값을 보다가..

quintus의 이미지

int main(int argc, char** argv){
int fd[argc];
int i;

for(i=0;i<argc;i+){
fd[i]=open(argv[i],O_RDWR);
printf("fd[%d]=%d\n",i,fd[i]);
}

return 0;
}

파일 디스크립터를 배열로 저장하고
그걸 프린트 했습니다.
근데 gdb 로 그 때 그 때의 배열의 값을 보니
printf 된 값과 다르게 나오네요. 어찌 된건지...

Quote:
$gdb a.out
(gdb)run *
(gdb)b 6
(gdb) print fd[0]
$1=0xbfff9c0
(gdb)next
fd[0]=-1
...........
(gdb) print fd[1]
$3=oxbfff9c1
(gdb)next
fd[1]=5

왜 gdb 에서의 print fd[0]값과
main 함수에서의 printf("fd[0]=%d",fd[0]); 값과 차이가 있죠..
cast 같은게 필요한건가요?
happibum의 이미지

6째줄에 breakpoint설정하시고
breakpoint에 걸리자마자 값을 출력해보셨는데
그때는 값이 아직 fd[0]에 들어가지 않은 때가 아닌지요?
printf문까지 왔을때, print fd[0]하면 제대로 나올듯합니다.

quintus의 이미지

Quote:
1 #include <fcntl.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4
5 int main(int argc, char** argv){
6 //int* fd=malloc(argc);
7 int fd[argc];
8 int i;
9
10 for(i=0;i<argc;i++){
11 fd[i]=open(argv[i],O_RDWR);
12 printf("fd[%d]=%d\n",i,fd[i]);
13 }
14
15 return 0;
16 }
~
~
~
~
~
~
~
~

Quote:
"test.c" 16 lines, 247 characters
cc: Error: test.c, line 7: In the declaration of "fd", "argc" is not constant, but occurs in a context that requires a constant expression. (needconstexpr)
int fd[argc];
-------^

혹시나 해서 컴파일 환경을 바꿔 유닉스에서 돌려 봤더니 저런 에러가 나오네요. const 가 아닌 값으로 배열의 크기를 정해주려하다 보니 그랬나봅니다.

malloc을 쓰니까 제가 원하는 대로 나오는데

Quote:
cc: Warning: test.c, line 6: In the initializer for fd, "malloc(...)" of type "int", is being converted to "pointer to int". (cvtdiftypes)
int* fd=malloc(argc);
--------^
또 이런 warning 이 나오네요.

근데

Quote:
$gdb a.out
(gdb)run *

(gdb) print fd[0]
$1=0xbfff9c0
(gdb)next
fd[0]=-1
...........
(gdb) print fd[1]
$3=oxbfff9c1
(gdb)next
fd[1]=5


위 디버그내용은 아마도 메모리의 주소 같거든요. oxbfff9c0 이니까 32비트.
그 메모리 값과 주소를 보려면 어찌 해야하는지..
alwaysrainy의 이미지

대략 난감 ㅡ.ㅡ;; happibum님께서 올려주신 답변을 전혀
고려치 않으셨네요..

제가 argc를 사용하여서 배열의 크기를 설정하는 것을 처음 보았는데요..
-Wall 옵션으로 컴파일해두 아무런 메시지가 뜨지 않는군요 ~ 본론으루 들어가서..

fd 배열이 선언되면 스택 영역에서 sizeof int * argc 만큼 메모리가 할당되고
초기화는 하지 않습니다. 당연히 쓰레기 값이 fd[0]에는 들어가 있을 수 밖에
없겠죠.. breakpoint를 6에 설정하심은.. fd[0]에 파일 디스크립터 번호값이
쓰여지기 이전에 break하라는 뜻이고 즉, fd[0]에는 여전히 쓰레기값이
들어가있겠죠..

(gdb) print fd[0] 
$1=0xbfff9c0 
(gdb)next 
fd[0]=-1 

b 7에 설정하시고 다시 실행시켜보세요.. 그리고 argv[0]은 실행 파일의
이름이겠죠.. argv[1]부터 시작하심이 적절할 듯.. 그리고 -1값이 들어있다함은..
파일 오픈에 실패했음을 의미합니다. O_RDWR 모드로 open 하였을 경우는
이미 존재하고 있는 파일을 읽고 쓰기 모드로 오픈입니다. 파일이 O_CREATE
모드도 or 연산으루 추가해주세요..

---------------------------------------
세계는 넓고, 할일은 많다.

최종호의 이미지

int fd[argc] 는 gcc 확장이거나 C99에 포함된 variable-length array 구문이네요.

static-length array와 어떻게 다를까해서 static-length array도 포함하도록 코드를 조금 수정했습니다.

#include <stdio.h>
#include <fcntl.h>

int main(int argc, char** argv)
{
        int fd[argc];
        int     ia[10];
        int i;

        for (i = 0; i < argc; i++) {
                fd[i] = open(argv[i], O_RDWR);
                printf("fd[%d]=%d\n", i , fd[i]);
        }

        return 0;
}

(gdb) ptype fd
type = int (*)[0]
(gdb) ptype ia
type = int [10]
(gdb) p fd[0]
$1 = 0xffbef388
(gdb) p fd[1]
$2 = 0xffbef389
(gdb) ptype fd[0]
type = int [0]
(gdb) n
12                      printf("fd[%d]=%d\n",i,fd[i]);
(gdb) n
fd[0]=5
10              for(i=0;i<argc;i++){
(gdb) p fd[0]
$3 = 0xffbef388
(gdb) p *fd[0]
$4 = 5
(gdb) p fd[0][0]
$5 = 5

실행결과를 보시면 int fd[argc]와 int ia[10] 의 타입을 다르게
생각하는 것을 보실 수 있습니다.
gdb는 fd 을 int (*)[0] 의 타입으로 보고 있습니다.
(이는, fd의 크기가 run-time시에 결정되기 때문인 것으로 보입니다.
같은 맥락에서 sizeof(fd) 도 run-time시에 그 값이 *evaluate*되겠죠.)

아마 실제 코드생성에서 gcc (gcc 이용하셨죠? 아님 linux에서 cc이용하셨거나요) 가 variable length array 를 elment type의 size 0인 배열에 대한 포인터 (int [0] 에 대한 포인터)로 잡고서
run-time시에 malloc()해서 공간을 할당받고
(음.. 구현들에서는 malloc이 아니라 stack에서 할당한다고 얼핏 들었던 것 같은데요. malloc이면 내부적으로 free를 불러줘야 할텐데, stack에 잡으면 별도로 free해 줄 필요가 없을 듯한데요. 배열 크기를 크게잡으면 stack 깨지지 않을까요?)

이후 fd[i] 에 대한 참조를 실제로는 *(*fd_internal + i) == fd_internal[0][i] 로 바꾼 것이 아닌가 합니다.

위 실행결과를 보시면
p fd[0][0]

이나

p *fd[0] (p (*fd)[0] 이 더 맞는 표현이겠으나, 현재 상황에서는 equivalent)

값이 5 를 리턴해 준다는 것이 이를 알려주고 있고요.

근데 여기서 좀 이상한 점은,
p fd[0]과
p fd[1]의 값이 틀려진다는 것입니다.
나중값이 현재값보다 1이 더 크지요.
gdb 는 int [0]의 크기를 0이 아니라 1로 생각한 것 같습니다.

gcc에서는 int[0]의 크기를 0으로 생각하고,
fd_internal[0] 과 fd_internal[1]의 값은 같게 처리됩니다.
아래 코드와 실행결과를 참조하세요.

/* Use gcc or C99 compliant compiler */

main()
{
        int     (*fd_internal)[0];
        printf("sizeof(int[0]) is: %d\n", sizeof(int[0]));
        printf("fd_internal[0]=%x, fd_internal[1]=%x\n", fd_internal[0], fd_internal[1]);
}

%  a.out
sizeof(int[0]) is: 0
fd_internal[0]=ffbef9dc, fd_internal[1]=ffbef9dc

제 테스트 환경은 다음과 같습니다. (gcc 버젼이 좀 낮네요.. ㅡ.ㅡ;;)
% gcc --version
2.95.3
% uname -a
SunOS hostname 5.8 Generic_108528-05 sun4u sparc SUNW,Ultra-80

음.. variable length array는 hidden cost (어느 분이 토론게시판에서 쓰신 표현이 좋아서 가져왔습니다.)가 있다고 봐야할까요?

quintus의 이미지

gdb) break 6
gdb) next

break 6 다음에 계속 next 하는 거였거든요.
제가 리눅스에서 프로그래밍 하구.. 인터넷을 설정을 못해서. 윈도우로 재부팅하구 손으로 코드를 치다보니까..실수 했네요..

제가 뭐가 잘 못 됐는지 너무 궁금해 하다가 시간이 지나면서 잊어버렸는데.. 오늘 갑자기 다른 컴파일러로 하면 어떨까라는 생각이 들어서 해 봤더니. 뭔가 실마리가 잡히는듯해서...

어쨌든.. 제가 설명을 제대로 못 해서 도움을 주시는 분한테도 혼란을 주게 됐네요. 그래도 오늘 이렇게 답변을 달아주셔서 너무 기쁘네요. 몇일 전에도 비슷한 글 올렸는데 제가 질문의 요지를 제대로 전달하지 못해서 그랬는지 궁금증을 해결하지 못했는데... 오늘 이렇게 답변 달아 주셔서 감사합니다. 이곳이 정말 큰 도움이 됩니다.

근데. gdb 상에서의 " print *fd[i] " 도 "printf("fd[%d]=%d\n",i,fd[i])" 와는 다르게 나오네요.
print *fd[0] 은 printf("fd[%d]=%d\n",i,fd[i])" 값처럼 나오는데
print *fd[1] 부터 해서
print *fd[i]는 예상치 않은 값이 나오네요..

맘 값아선. gdb 한 내용들을 다 올려보고 싶은데.
리눅스 인터넷 설정도 못 하겠고. 그래픽 카드도 못 잡았고. 또 윈도우xp에선
어떻게 mount 시키는 지도 모르고..
나중에 제가 컴퓨터 다 설정하고 나서 gdb 한 내용을 다시 한번 올리겠습니다.

댓글 달기

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