리눅스 아주 간단한 c코드 인데요 read함수에서 왜 에러가 나는지 모르겠습니다.ㅜㅜ 도와주세요.

inviolable의 이미지

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
 
int main(int argc, char *argv[])
{
        int fd1 = open("buffer1",O_RDWR | O_CREAT | O_TRUNC,0777);
        printf("%sn",argv[1]);
        write(fd1,argv[1],10);
        lseek(fd1,0,SEEK_SET);
 
 
 
        int check = read(fd1,argv[2],10);//여기서 왜 read에러 나는건지요ㅜㅜ 에러날 이유가 없는 거 같은데...
        if(check == -1)
        printf("read errorn");//이게 출력이 됩디다...
 
 
 
        printf("%dn",argc);
        printf("%sn%sn",argv[1],argv[2]);
        return 0;
}
freemckang의 이미지

코드를 돌려보진 않았지만, code에서 error가 발생할 경우 strerror(3) 등을 이용하면 좀 더 쉽게 error의 원인에 접근할 수 있을 겁니다. 예를 들어

printf("Error : %s\n", strerror(errno));

정도면.. 더 쉽게 분석이 가능하실겁니다. 아울러, 어떻게 인자를 넘겼는지 정도도 한번 확인해보시죠 :)

句日新, 日新 日新 又日新.

kjr8318의 이미지

c언어는 변수 선언이 맨 처음에 이루어 져야 하는것으로 알고 있는대
지금 보니
int check = read(fd1,argv[2],10);
이곳에 바로 선언 되어있내요 그래서 에러가 나는것 같아 보입니다
틀릴것일수도 있구요

inviolable의 이미지

매개변수로 넘어오기 때문에 char *argv[] 자체가 선언 되어있다고 볼 수 있지 않나요???
실제로 argv[2]="hello" 이런식으로 초기화는 되더군요... 선언 없이요.
근데 그렇게 초기화해줘도 read에러가 나더군요... argv[2]가 분명히 존재하는데도... 왜 그럴까요???
프로그램 실행해봐도 argv[2]값은 hello로 출력이 됩니다... 근데 read로 문자열 넣는게 안되더군요...

익명 사용자의 이미지

$ ./a.out 1234567890123 ABCDEFGHIJKLM
1234567890123
3
1234567890123
1234567890KLM
$  ./a.out 1234567890123
1234567890123
read error
2
1234567890123
(null)
$

잘 되는데요. 뭐가 문제라고 생각하시는지요?
klyx의 이미지

argv[argc]는 널입니다.

inviolable의 이미지

물론 제가 교수님의 의도를(어떻게 파일을 만들라는) 걸 잘못이해해서 인수를 1개만 넣는 실수를 한거지만(2개 넣어야됩니다. 그래야 1에서 2로 복사됩니다. 파일이름 제외)

막상 코딩을 하고보니 2가지 의문점이 생깁니다.

1. char *argv[]의 크기는 프로그램 실행시 넣어주는 인수의 크기와 관련되는가?

2. 코드상에서 argv[2] = "hello\n' 에서는 문제 없이 초기화가 됐는데(main함수 맨처음에 argv[2] = "hello\n" 추가해보세요.) 왜 read는 에러가 나는가(argv[2]가 분명히 존재하는데).

이 두가지 의문점이 생기네요...

klyx의 이미지

argv[argc]는 널이라고 앞에 달았습니다. 흔히 null-terminated array 라고 하는 녀석입니다.
그리고 argv[2] = "hello\n" 초기화가 아니고 포인터에 대한 대입이며, 심지어 이걸 read의 읽기 버퍼로 쓴다는 건 절대로 해서는 안되는 일입니다.

inviolable의 이미지

argv[2]가 char* 형이고 문자열도 char* 이며, 읽기나 쓰기 버퍼로 쓰이는 배열도 char*형이니 상관 없지 않나요???

freemckang의 이미지

Linux programming 공부도 중요하지만, C로 code를 짜신다면, C언어에 대해서도 공부를 하시면 이런 문제에 대해 이해가 빠를 듯 하네요 :)

C code를 컴파일/링킹해서 ELF와 같은 실행파일을 얻으면 objdump와 같은 툴을 사용해서 내용을 분석해보시면 도움이 될 듯 합니다. 변수로 선언한 char *가 memory의 어느 section에 위치하는지... 큰 따옴표로 감싸져있는 일반 string은 어느 section에 위치하는지... 그 section이 의미하는 것은 무엇인지..

이것에 대한 답을 드릴 수 있는 분은 이곳에 굉장히 많겠습니다만, 공부하시는 학생분이신 것 같아서 직접 찾아보시길 권해드립니다.. 좋은 공부가 될겁니다 :)

句日新, 日新 日新 又日新.

inviolable의 이미지

그래도 대충 쉽게 답변해주시면 더 감사했을텐데.ㅎㅎ;;;

아랫분이 답변을 줬는데 나중에 한번 더 찾아봐야겠네요 답변 감사합니다.

hiseob의 이미지

open/read/write/close 다시 공부 하세요. 뭔가요 이게.

딱 보니까 잘 몰라서 파일을 open 해야되는데 버퍼랍시고 buffer 를 open 하고 매개변수를 버퍼랍시고 read 걸고 있네유 ㄸㄸㄸㄸ

파일 사이즈 확인하고 malloc open read write close free 로 가야될거 같은데 ㄸㄸㄸㄷ

inviolable의 이미지

buffer1이라는 파일을 현재 디렉토리에 만듭겁니다. O_CREAT 플래그가 붙어있습니다.

horong54의 이미지

코드의 의도를 전혀 모르겠구요.
설마 인수를 두개 받아서 첫번째 파일의 내용을 두번째 파일로 복사하는 소스는 아니겠지요???

그렇게 하려면

일정 크기의 버퍼 선언 char buf[64] 라던가...
fd1 = 인수1로 파일 오픈 (읽기 모드로) --> 파일이 존재하지 않으면 에러 메시지 출력후 프로그램 종료
fd2= 인수 2로 파일 오픈 (덮어쓰기 가능하게)

while(fd1 다 읽을 때까지)
read (fd1 내용을 buffer에다 읽는다.) // 한번에 버퍼의 크기만큼 읽습니다.
write (buffer 내용을 fd2에 쓴다.)

정상적으로 잘 처리됐으면 두 파일 잘 닫고 프로그램 종료한다.

이런식으로 되어야 합니다.

책을 읽어보시고, 책이 없으면 linux의 man 페이지를 보시면 함수 설명이 잘 나옵니다.
책은 리눅스 시스템 프로그래밍 또는 고급 유닉스 프로그래밍 두 권 추천합니다.

inviolable의 이미지

프로그램 실행시 a.out aaab 이렇게 쓰면 첫번째 인수가 2번째 인수로 복사되는 것입니다.

그 후에 argv[1] argv[2]를 출력하게 되어있죠. 복사가 잘 됐는지 안됐는지 확인을 위해.

부끄럽습니다만 현재 공부는 하고 있습니다. 학교에서 유닉스 프로그래밍 과목을 다루고요. 제 나름대로도 책도 봐가면서 열심히 하고 있습니다.

근데 인수를 1개 써서는 도저히 안되더군요 2개를 써야 복사가 되는데요...

argv[argc]가 널인 것을 확실히 한다 책에는 이렇게 나와있는 걸로 봐서 제가 글로 올린 코드로 쓰면 오류가 난다는 걸 이해는 하겠는데요...

main함수 처음 부분에 argv[2]을 초기화해주면서 생성을 해줘도 read(파일 -> argv[2](버퍼로 씀))가 안되는 건 왜 그럴까요?? argv[2]는 분명히 출력이 되고요(코드에서 초기화해준 값으로)... 그렇다면 argv[2]라는 놈이 2개 인데 read에서는 main함수 인수로 받은 놈만을 쓴다는 건지 이 부분을 잘모르겠네요...

yhsuk의 이미지

코드의 의도가 첫번째 인수를 두번째 인수로 복사하는 것이면 파일은 왜 여는건가요?
그리고 argv나 argc는 프로그램 실행명령을 줄 때 고정되는 값인데, 이 값을 수정하려 하는 의도도 모르겠네요(물론 파일의 읽기버퍼로 써도 안되고)
문제가 책에 나와있는 거라면 책의 텍스트 내용을 쓰는게 오해를 줄일 수 있겠네요.

그리고 main함수 진입시 이미 argv 배열의 크기는 고정되어 있습니다. 인수를 하나만 주고 argv[2]를 접근하는 것은 하면 안됩니다.
그리고 오류가 발생하지 않고 넘어간다 해도 파일의 읽기 버퍼로 쓰는 것은 문자열 상수를 수정하는 것이라 또 안됩니다.
일전에 답글 단 내용인데 확인해 보세요

http://kldp.org/node/134612

Signature :) - "여유를 갖고 행동하되 게을러지지 말자"

inviolable의 이미지

read,write,lseek정도 이용해서 argv[1]을 argv[2]로 복사해야 되거든요... 이 함수를 이용해서 복사할려면 파일 하나 생성해서 argv[1]을 그 파일에 쓰고 그 파일에서 argv[2]로 읽어서 복사하는 방법이 생각나서 그 방법을 적용한 거였고요... 저 3가지 함수 이용해서 하려면 방법이 많을 것 같지는 않은데요...

그냥 교수님이 내신 문제였어요. read,write,lseek배웠으니까 그 함수들 이용해서 3개 정도 문제 낼 테니까 한번 해봐라 1하고 2는 했는데 3번째가 argv[1]을 argv[2]로 복사하는 문제였어요.

아 argv[2] = "hello"하고 초기화하는 순간 argv[2]는 문자열 상수를 가리키고 있으므로 수정이 불가능하다는 말씀이군요. 링크도 보았는데... 아 이제 이 부분은 이해가 되는군요.

답변 감사합니다. 이해가 잘 된 것 같습니다 감사합니다 (__)꾸벅

익명 사용자의 이미지

예제로 올려주신 코드가 아주 나쁜 코드라고 봅니다만, 일단 그 안에서 왜 그런가 살펴본다면

말씀하시는 상황에서 read(fd1, argv[2], 10); 가 에러가 나는 이유는:
1. argv[2] 가 null 인 경우.
2. argv[2] 가 null 은 아니지만, argv[2] 가 가르키는 메모리 블럭이 10바이트의 데이터를 쓰기에 적합하지 않은 경우입니다.

read() 앞에서 argv[2]를 출력해서 확인해 보시기 바랍니다.

     printf("argv[2]=0x%08X \"%s\"\n", argv[2], argv[2]);
     read(fd1, argv[2], 10);

아닌 경우 있으면 예제코드를 올려보세요.

inviolable의 이미지

아무런 초기화 없이 인수를 argv[1]하나만 줘서 해보면 argv[2]는 널값으로 잡히고, 코드 내에서 초기화를 해주면 그 값으로 잡히는데 문제는 read의 버퍼로는 쓸 수 없다는 점입니다. 그 이유는 위의 분이 설명해줘서 알것 같네요.

답변 감사합니다.

hiseob의 이미지

자 보세요.

a.out argv1 argv2 이런식으로 해서 argv1 -> argv2 복사할려면

origsize = filesize(argv[1]); // 가상의 함수 이런거 있음

buffer = malloc(origsize);

origfd = open(argv[1], O_RDONLY);

read(origfd, buffer, origsize);

tofd = open(argv[2], O_WRONLY | O_CREAT, 0777);

write(tofd, buffer, origsize);

close(origfd);
close(tofd);
free(buffer);

이런식으로 되어야 한다구요

char *argv[] 의 의미를 다시 생각해 보세요..... 도대체 왜 argument 가 들어있는 공간에 write 가 될거라고, write 가 된다 하더라도 그게 지금 맞는 사용법일거라고 생각하는겁니까?

man read, man write 해보세요. argv[2] 라고 해놓으신 자리에 뭐가 들어가야 맞는건지 알수 있으실겁니다.

에러가 날 이유가 없는것 같다니... 거 참.... 한마디로 RTFM 입니다.

inviolable의 이미지

교수님이 write, read, lseek 이용해서 하라고 하셔서 malloc까지 써야되는지는 몰랐네요(물론 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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.