리눅스용 프로그램 유닉스에서 안돌아가네요(해결했음-감사합니?
해결했습니다~ 원인은 ㅡㅡ;;;
왜 파일명을 test.c 로하여 test라는 파일명으로 지어주니
실행이 안되는 것일까요?
예약어였던 모양인데..
참으로 죄송하게 되었습니다.
해결이 되었기에 그 원인을 적고자...
앞으로도 많은 도움 부탁 드립니다.
아, 그리고 답변이 새로 올라왔네요 ^^
유닉스는 현재 디렉토리가 패스로 걸리기도 하는가 보군요.
패스가 앞에 걸린곳과 뒤에 걸린곳에 동일명의 파일이 있으면
앞에 걸린 곳에서 실행된다는 것을 또 배웠네요 ^^
리눅스에서 테스트까지 다 끝내고 유닉스로 복사해 와서 프로그램을 돌려
보았는데 돌아가지를 않는군요..
(밑의 답변을 참고로 하여 gcc로 컴파일 하였더니 argc-1도 컴파일이 되더군요
몰랐을 때는 argc-1이 상수값이 아니라기에 100으로 바꾸어 썼었습니다.
컴파일은 되었으나 실행시키면 다시 % 프롬프트로 떨어집니다.)
제가 알고 있는 선배들이나 어른들께 질문을 드려도 거기까지는 잘 모르시는
건지 답을 알수가 없구요..
책을 찾아 보아도 대체 어디를 보아야 이에 대한 답을 알 수가 있는 것인지..
제가 시도해 보며 찾아 내는것이 당연함을 앎에도 불구하고
시간이 하염없이 흘러감에 꼭 도움을 받아야 겠다고 생각하여
글을 올리게 되었습니다.
24세 어쩌면 (조금은) 늦은 나이에 리눅스 프로그래밍에 손을 대기
시작했지만 꼭 이곳의 많은 분들과 대화를 나눌수 있는 수준까지 올라가
보고 싶네요.
간단한 소스이니 코드를 붙입니다.
내용은 별거 없고 길이만 긴(불필요 내용이 많이 반복되는) 프로그램입니다.
주석문도 제 짐작으로 붙인 것이 많아 틀린것이 많을지도.
그리고 게시판의 질문들을 쭉 검색해 보았는데요 포팅이란 말이 나오던데
변환작업을 말하는 것인지..?
유닉스용 프로그램을 리눅스에서 돌리는 것에 대해서는 글이 몇개 있었는데
그것에 대해서도 궁금하군요. 원래 리눅스용 프로그램을 유닉스에서 돌리는
일이 별로 없는 것인가요?
// 와우리눅스 7.3 파란 R2에서 테스트 완료. //임의의 갯수만큼 복사하기 //실행파일명 원본파일명 목적파일명1 목적파일명2 ~ 목적파일명n // 위의 주석문을 주석처리 안할시 헤더파일에 관한 해석불가능 에러가 발생하였다. ㅡㅡ;; #include <stdio.h> #include <fcntl.h> void smenu(); void tofile(); void toscr(); void toall(); void input(); char buf[BUFSIZ]; // BUFSIZ는 헤더에 정의 되어 있는 듯하다. 따로 정의하면 // 재지정 에러가 발생한다. main(int argc, char *argv[]) // 첫번째는 실행파일, 두번째는 원본,세번째부터 98개까지 목적파일. { //int n,i,fd[argc-1]; // 배열의 0번칸은 읽을 파일이, 1번칸부터 쓸 파일명이 들어간다. int n, i, fd[100]; // 유닉스에서 상단의 문장이 통하지 않아 하단의 문장을 사용하였음. printf("\n\ntesting, testing.... argc = %d\n\n",argc); if(argv[1] == '\0') printf("\n"); else if( strcmp(argv[1],"--help") == 0 )// strcmp사용시 첫문자가 널이면 세그먼테이션에러. { printf("화일및 문자열을 복사하는 프로그램입니다.\n"); printf("화일의 복사 : 실행파일명 원본파일명 목적파일명1 목적파일명2 ..목적파일명n\n"); printf("문자열의 복사 : 실행파일명입력후 나오는 메뉴를 선택 바랍니다.\n\n"); exit(0); } if(argc == 1) { smenu(); exit(0); } else if(argc == 2) { printf("도움이 필요하시면 실행파일명 --help를 쳐 주세요"); exit(0); } else printf(" 파일 복사 작업에 들어 갑니다.\n"); for(i = 2 ; i < argc ; i++) // i=2인것은 첫번째인수는 실행파일, 두번째인수는 원본파일이기때문. { fd[0] = open(argv[1], O_RDONLY); // 배열의 첫째 칸에 읽을 파일의 핸들을 할당. fd[i-1] = open(argv[i], O_WRONLY | O_CREAT , 0777);// 배열의 둘째칸(최초는fd[1])부터 목적파일명의 // 핸들을 할당.i값의 증가에 따라 증가되어간다. // 주의 : read함수는 이전에 읽었던 부분을 기억하고 있으므로 파일을 루프 전에 한번만 // 열어주면 두번째 루프부터는 화일의 맨 끝부터 읽으려 하므로 아무것도 읽지를 못한다. // 해결법중 하나로 루프가 돌아갈때마다 파일을 열어 주도록 하였다. while((n=read(fd[0], buf, BUFSIZ)) > 0) write(fd[i-1], buf, n); close(fd[i-1]); close(fd[0]); } close(fd[0]); printf("\n\n작업이 완료 되었습니다. 다른 작업을 원하시면 프로그램을 재실행해 주세요\n"); } /*-----------------------------------------------------------------------------------------*/ /* 메뉴 선택을 위한 함수 smenu() */ /*-----------------------------------------------------------------------------------------*/ void smenu() // 문자열 작업의 메뉴 선택 함수입니다. { char menu,tmp ; printf("\n\n문자열 관련 작업을 선택하셨습니다.\n"); printf("타이핑한 문자의 파일로의 출력, 화면으로의 출력, 화면과 파일로의 출력이 가능합니다.\n"); printf("타이핑한 문자의 파일로의 입력이 가능합니다.\n"); printf("읽어들일 파일의 이름을 지정하실수 있습니다.\n"); printf("기록할 파일의 혹은 파일들의 이름을 지정하실수 있습니다.\n"); printf("엔터 키를 눌러 주세요\n"); while(1) { menu = '7'; while( !((menu >= 49)&&(menu <= 53))) { tmp = getchar(); // 키보드 버퍼의 null(혹은 공백?)을 뽑아내기 위하여 사용ㅡㅡ; //부함수에서 돌아올때 버퍼에 하나가 더 들어오는듯함. 그것을 뽑아내기 // 위하여 사용 ㅡㅡ;;;; printf("\n\n\n\n\n해당 작업의 번호를 선택해 주세요.\n"); printf("1. 타이핑한 문자의 파일로의 출력\n"); printf("2. 타이핑한 문자의 화면으로의 출력.\n"); printf("3. 타이핑한 문자의 파일과 화면으로의 출력.\n"); printf("4. man페이지에 mycopy0.8추가.\n"); printf("5. 프로그램을 종료 합니다.\n"); printf("바른 입력값이 나올때까지 입력을 받습니다.[ ]\b\b\b"); menu = getchar(); // tmp = getchar(); // 키보드 버퍼의 null(혹은 공백?)을 뽑아내기 위하여 사용ㅡㅡ; } switch(menu) { case '1' : tofile(); break; case '2' : toscr(); break; case '3' : toall(); break; case '4' : input(); break; case '5' : printf("프로그램을 종료합니다.\n"); exit(0); } } } // 메뉴함수 종료부분. /*--------------------------------------------------------------------------------------------*/ // 타이핑한 문자의 파일로의 출력을 위한 함수 tofile() /*--------------------------------------------------------------------------------------------*/ void tofile() { int fd, n; char fname[20]; printf("입력받은 문자열을 파일에 기록하는 작업을 수행합니다.\n"); printf("기존에 있는 파일명을 지정할 경우 기존의 내용은 삭제됩니다.\n"); printf("대상 파일명을 적어 주세요.(영문19자한글9자내로 적어 주세요.)\n"); /* gets(fname);에러가 발생하므로 보류.에러가 왜 나지 ㅡㅡ;;*/ scanf("%s",fname); //gets를 사용하고 싶었으나 에러를 해결 못하고 scanf사용. printf("%s",fname); fd = open(fname, O_WRONLY | O_CREAT, 0777); printf("입력할 내용을 적어 주세요.더이상의 입력을 원치 않으실 경우 Ctrl + z 키를 눌러 주세요\n"); printf("Ctrl+z키는 파일 전체의 실행을 중단시킵니다.\n"); while(1) { printf("%s\n",buf); n = read(1, buf, BUFSIZ); write(fd, buf, n); } close(fd); printf("작업을 끝마쳤습니다.\n"); } /*------------------------------------------------------------------------------------------*/ // 입력받은 문자의 화면 출력을 위한 함수 toscr() /*------------------------------------------------------------------------------------------*/ void toscr() { char data[BUFSIZ]; printf("입력 받은 문자를 화면에 출력 합니다.\n"); printf("임시 버퍼를 사용하지 않으므로 한번에 한 줄씩만 사용이 가능합니다.\n"); scanf("%s",data); printf("%s\n",data); } /*------------------------------------------------------------------------------------------*/ // 입력받은 문자의 화면및 파일 출력을 위한 함수 toscr() // 파일 출력함수와 몇 줄만 차이가 나나 복사하기가 편하여 분리하였음. // 하나의 함수와 넘겨받은 인수를 이용한 if else문이 효율적일듯 함. /*------------------------------------------------------------------------------------------*/ void toall() { int fd, n; char fname[20]; printf("입력받은 문자열을 파일과 화면에 기록하는 작업을 수행합니다.\n"); printf("기존에 있는 파일명을 지정할 경우 기존의 내용은 삭제됩니다.\n"); printf("대상 파일명을 적어 주세요.(영문19자한글9자내로 적어 주세요.)\n"); /* gets(fname);에러가 발생하므로 보류.에러가 왜 나지 ㅡㅡ;;*/ scanf("%s",fname); //gets를 사용하고 싶었으나 에러를 해결 못하고 scanf사용. printf("입력될 파일명은 %s",fname); fd = open(fname, O_WRONLY | O_CREAT , 0777); printf("입력할 내용을 적어 주세요.\n더이상의 입력을 원치 않으실 경우 Ctrl + z 키를 눌러 주세요\n"); printf("Ctrl+z키는 파일 전체의 실행을 중단시킵니다.\n"); while(1) { n = read(1, buf, BUFSIZ); write(fd, buf, n); printf("파일에 입력되는 내용은 "); write(1, buf, n); printf("\n"); } close(fd); printf("작업을 끝마쳤습니다.\n"); } /*------------------------------------------------------------------------------------------*/ // 입력받을 원본파일을 기록할 예정이었으나 도중에 상단의 기록 메뉴와 같음을 깨닫고 --; // man페이지 추가 함수로 변경함. /*------------------------------------------------------------------------------------------*/ void input() { printf("\n\n\n\nman 페이지 추가 메뉴는 기술 부족으로 미완성입니다.\n"); printf("별첨된 mycopy.1.0.8.gz파일과 mycpmset파일이 있다면 mycpmset을 실행시키세요 \n"); /* int fd; char *str = " mycopy0.8의 man페이지 입니다.\n\ \n\ \n\ \n\ 사용법\n\ \n\ mycopy0.8 엔터 -> 문자열의 복사 모드로 들어 갑니다.\n\ mycopy0.8 인수1 -> 도움이 필요 하시면 --help를 타이핑 하세요 ^^\n\ mycopy0.8 --help -> 간략한 도움말이 나옵니다.\n\ mycopy0.8 인수1 인수2 ~ 인수n -> 인수의 갯수(n)개만큼 인수1의 파일이 복사됩니다.\n\ 즉, 인수1은 원본파일, 인수2 ~ 인수n은 사본명이 됩니다.\n\ \n \ \n \ 텍스트 모드 사용법\n\ \n\ 1. 타이핑한 문자의 파일로의 출력\n\ \n\ -> 처음에 출력할 파일명을 지정한후 한 라인씩 차례대로 입력합니다.\n\ 종료시에는 Ctrl + z 키를 이용하게 되는데, 이는 \n\ 시스템에서 기본적으로 제공하는 키로, 파일의 수행을 중단시킵니다."; //fd = open("a", O_WRONLY | O_CREAT, 0777); fd = open("/usr/share/man/man1/mycopy.1.0.8.gz", O_WRONLY | O_CREAT, 0777); write(fd, str, sizeof(*str)) ; close(fd); */ }
무슨 에러인데요? 컴파일이 안 되는 건지, 컴파일은 되는 건데 실행이 다
무슨 에러인데요? 컴파일이 안 되는 건지, 컴파일은 되는 건데 실행이 다르게 되는 건지 적어주셔야죠.
그리고 코드는 BBCODE를 이용해 적어주시면 그나마 보기에 좋답니다.
어떤 문제인지는 모르겠습니다만, 우선 눈에 띄는 코딩 습관의 실수부터 지
어떤 문제인지는 모르겠습니다만, 우선 눈에 띄는 코딩 습관의 실수부터 지적해봅니다.
우선 argv[1]은 pointer입니다. '\0'과 비교하지 말고 NULL 과 비교해야 합니다. 그리고 이 부분은 알아보기 쉽게
if(argc==2 && strcmp(argv[1],"--help") == 0 )
식으로 쓰는 것이 어땠을까요?
이런 목적을 위해서 lseek 함수가 있습니다. 그리고 굳이 open/close 등의 system call을 쓴 이유가 있나요? 그냥 fopen/fclose(그리고 fseek)의 C 함수를 사용하세요.
유닉스에서 Ctrl-Z는 실행 중단이 아닙니다. 원 프로세스는 계속 살아있는 상태에서 잠시 중단하는 것이 아닙니다. 실행 중단을 원하는 것이라면 Ctrl-C를 눌러야죠.
gets 함수는 overflow 에러가 날 가능성이 있으므로 Linux 등에서는 컴파일 시에 "경고"가 나옵니다. (에러는 아닐텐데요?) scanf도 같은 문제가 있습니다. 피하려면 fgets를 사용하셨어야 합니다.
Linux C 코드의 Unix 이전..
POSIX 를 만족한다면 대부분은 문제 없습니다만,
같은 POSIX 여도 OS 따라서 약간의 Side-Effect 를 보이는
경우가 있습니다..이점을 일단 확인하는게 필요하구요..
Unix 로 옮길때 컴파일 에러가 난다고 하셨는데...
그쪽 Unix 에서도 gcc 를 사용하는게 아니라면,
코드 그대로는 컴파일 되질 않겠군요.
'//' 주석은 C 에서는 허용되질 않습니다.
C99 에서 표준이 되었지만, 아직 C99 를 지원하는 컴파일러가 별로 없기에
해당 Unix 시스템에 있는 C 컴파일러가 '//' 주석을 제대로 처리해 주지
못할 것으로 보입니다.
또한, main() 함수의 첫부분의 주석에서
int fd[argc-1] 이 동작하지 않는다고 하셨는데
이 역시 현재는 gcc 에서만 지원하고 있습니다.
이 구문 역시 C99 에서 표준이 되었지요.
물론, 컴파일시의 컴파일러가 표시하는 에러 메세지를 적어주셔야
정확한 원인을 파악할수 있겠습니다.
질문이 부족하였던 관계로 보충질문입니다.
____________________________________________________
위의 답변사항을 읽고 나름의 수정을 하였습니다. 바꾼 부분이 거의 없으니
(gcc가 있더군요 유닉스에.)
거의 같으며, '\0'에서 NULL로만 바꾸어 주었습니다.
참고로 처음에 났던 컴파일 에러는 argc-1이 상수값이 아니라는 ^^
것이었기에 100으로 수정하였다가
gcc로 컴파일 하면 된다고 하시기에 gcc로 했더니 argc-1이 통하네요
lseek부분과 if문에 관해서, 그리고 fgets에 대하여
(그리고 fopen/fclose에 관해서는 아직 이해를 못했으나. 제 지식에
구멍이 많군요 ^^ 그것도 꼭 공부해 보도록 하겠습니다.)
말씀해 주신것 정말
큰 도움이 되었습니다. 그러나 지금 유닉스에서 실행시키는 것이 우선이라^^
다른 문제점이 생길까 두려워 손을 대지 않았습니다 ^^
고친 후에도 여전히 컴파일은 되나 실행을 시키면
%프롬프트가 다시 떨어지는군요.
아시는 분이 계시다면 번거로우시더라도 답변 부탁드립니다.
____________________________________________________
덧붙인 글은 사족이네요
컴파일시의 에러는 제가 다 처리했다고 생각합니다.
앞글에 주석과 같이 적혀 있는 argc-1부분하나만 컴파일 에러가
발생하였고 그것을 해당 코딩부의 바로 아래부분과같이 처리를 하여
해결하였습니다.
제목이 도중에 잘려 의미전달이 안된듯 합니다. 원제목은
유닉스에서 재 컴파일시 나는 컴파일 에러는 모두 잡았다는 내용입니다.
실행시키면 아무 화면도 나오지 않고 다시 프롬프트가 떨어 지는군요.
그리고 글을 작성한 후 코딩부를 녹색 글씨로 적어야 한다는 사실을 알았으나
고치는 방법을 알수가 없어 어쩌지를 못하였음에 죄송하다는 말을 드리고 싶
군요.(지금 '편집'키를 찾았습니다 ^^)
지적해 주신 사항들에 대하여 수정해 보았습니다.
일단 유닉스 시스템에 gcc를 실행시켜 보니 gcc가 있더군요 ^^
저는 gcc가 리눅스에만 있는 것인줄 알았습니다.
gcc가 있으므로 기존의 주석문들은 코딩을 그대로 두었고,
위에서 지적해 주신 argc-1도 회복시켜 argc[100]을 없앴습니다.
그리고 지적사항대로 생각해 보니 argv[1]은 포인터가 맞더군요 ^^
그걸 왜 '\0'과 비교하려 했었는지....^^
그것도 NULL과 비교하도록 수정하였습니다.아마도 NULL은 헤더파일에
디파인문으로 정의가 되어 있는 것이겠죠?
(무엇으로 정의가 되어 있을지는 짐작이 안가네요. 무언가의 포인터인가요
이 문제를 해결하는대로 한번 찾아봐야 할듯.)
타인을 자기 자신처럼 존경할수 있고, 자기가 하고 싶다고 생각하는 것을 타인에게 할 수 있다면, 그 사람은 참된 사랑을 알고 있는 사람이다. 그리고 세상에는 그 이상 가는 사람은 없다.
test
test 라는 실행명령이 존재하는 걸로 압니다.
아규먼트를 받아서 해당 아규먼트를 검사해서 true or false 를 리턴하는
명령 같더군요.
리눅스 시스템이였다면 현재 디렉토리가 패스에 잡혀있질 않으므로(기본적으로)
./test 로 실행을 했다면 문제 없었겠지만..
유닉스 시스템들은 현재 디렉토리가 패스에 잡혀있는 경우가 있더군요..
물론, 맨 마지막에 잡혀있기 때문에, /bin 같은 디렉토리의 명령과 이름이 겹치면
그 녀석이 실행되죠..
그리고 NULL 은 stdio.h 에서 정의합니다.
정확하게 뭘로 정의하는지 기억은 안나는데..
(char *)0 이나 (void *)0 과 비슷한 의미였던거 같습니다.
댓글 달기