brunch

매거진 Sinclair

You can make anything
by writing

C.S.Lewis

by Sinclair Feb 11. 2016

함수와 함수의 활용

그는 나에게로 와서 꽃이 되었다 II




main()함수의 인자와 리턴 값 활용하기  


C언어에서 모든 함수의 시작인 main()도 함수입니다. 함수는 누군가 불러 주었을 때 그에게로 가서 꽃이 된다고 했습니다. main()함수를 불러보신 적 있으신가요? 전 안 불렀는데요? 그럼 누가 부르죠? 그건 바로 OS가 부르는 것입니다. 우리가 명령 행에서 직접 프로그램이름을 타이핑 하거나 또는 실행 프로그램을 마우스 더블 클릭을 하게 되면 OS는 그 프로그램의 main()를 호출 하게 됩니다.


Unix를 비롯한 대부분의 OS가 핵심부분은 C언어로 작성이 되어있다는 것을 생각하면 OS가 가장 먼저 main() 함수를 부른다는 것은 쉽게 이해할 수 있을 것 입니다.                                



main()함수의 인자들


main();

main(void) ;

명령행 인자를 사용하지 않는 경우 입니다.



main(int argc , char ** argv) ;

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

명령행 인자를 활용하는 경우 입니다.


argc는 인자의 개수를 말하고 argv는 실제 인자 문자열 값들 입니다.

dir /p 나 ls -al 과 같이 실행 시 인자를 실행 프로그램에 넘길 수 있습니다. 물론 옵션 기능으로 처리하는 것이 보다 효율적입니다.



main(int argc , char ** argv , char ** envp ) ;

main(int argc , char * argv[] , char * envp[] ) ;

명령행 인자와 환경변수를 활용하는 경우 입니다.


envp는 환경변수 문자열 전체를 받습니다. 환경변수는 OS가 실행되는 환경에 대해 정의된 값들입니다. 그리고 환경변수 문자열의 마지막에는 NULL문자열이 들어있습니다. 이것을 활용하여 인자뿐만 아니라 현재 프로그램을 위한 새로운 환경변수를 정할 수 있습니다. 변경된 환경변수는 현재 프로그램에서만 적용되므로 프로그램이 종료하기 전에 환경변수를 복구하지 않아도 됩니다. 현재 일부 OS와 컴파일러에서 제공하고 있습니다.



명령행 인자 활용하기  


#include <stdio.h>  

/*

* copyleft (l) 2006 - 2017 programmed by Sinclair

*/   

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

    register index ;

    if( argc == 1 ) {

        printf("%s needs some arguments..\n" , *argv ) ;

        return 0 ;

    } // end if  


    printf("%s%d\n" , "the number of arguments = " , argc ) ;


    for ( index = 0 ; index < argc; index++ )    {

        printf("%d \t %s\n" , index , argv[index]) ;

    } // end for


    return 0 ;  


} // end main()    




실행프로그램명 Sinclair 1 2 3 안녕하세요? <- 이렇게 실행해 보면 결과를 확인 할 수 있습니다.   

main()함수를 호출하면 OS는 바로 들어오는 인자의 개수를 세고 char * argv[argc]의 배열을 할당하고 각 배열의 요소(방)에 호출할 때 넘어온 인자들의 시작 주소 값을 세팅하게 됩니다. main()도 함수인데 달라지겠습니까? 일반함수처럼 똑같이 인자도 부르는 쪽에서 주는 것이고 함수 실행 후 결과에 해당하는 리턴 값도 호출한 쪽이 받는 것입니다.


argv[0] == 실행프로그램명의 주소 값

argv[1] == 첫 번째 인자인 문자열 "Sinclair"의 시작 주소 값

argv[2] == 두 번째 인자인 문자열 "1"의 시작 주소 값

argv[3] == 세 번째 인자인 문자열 "2"의 시작 주소 값

argv[4] == 네 번째 인자인 문자열 "3"의 시작 주소 값

argv[5] == 마지막 인자인 문자열 "안녕하세요?"의 시작 주소 값  


모두 문자열로 입력된다는 사실을 꼭 기억해야 합니다. 만약에 숫자가 필요하면 atoi()나 atof()를 사용하여 변환해야 합니다.   




세 번째 인자를 사용해 환경변수 확인하는 프로그램  


#include <stdio.h>  

/*

* copyleft (l) 2006 - 2017 programmed by Sinclair

*/   

int main(int argc, char ** argv, char ** envp ) {

    int index ;

    char ** envPointer = envp ;  

    while( * envPointer )

        puts(*envPointer++) ;

    return 0 ;

} // end main()    




외부 변수를 사용해 환경변수 확인하는 프로그램  


#include <stdio.h>  

/*

* copyleft (l) 2006 - 2017 programmed by Sinclair

*/   

extern char ** environ ;  


int main(int argc, char ** argv) {

    int index ;

    char ** envPointer = environ ;  

    while( * envPointer )

        puts(*envPointer++) ;

    return 0 ;  

} // end main()    




환경변수는 프로그램이 실행되는 OS(운영체제)의 환경을 미리 정해 놓은 것입니다.

GNU-Linux나 Windows의 set명령어를 사용하면 현재 OS의 설정되어 있는 환경변수들을 확인 할 수 있습니다.


우리는 지금까지 main()함수의 인자들에 대해서 함께 알아보았습니다.

그렇다면 main()함수의 리턴 값은 누가 받을까요? 그것은 바로 main()함수를 부르는 쪽에서 받을 것입니다.


main() 함수는 OS가 부른다고 했습니다. 그러니 OS가 받게 됩니다. OS는 그 리턴 값으로 프로그램이 정상 종료 했는지 비정상 종료 했는지, 또 비정상 종료의 원인이 무엇인지 알 수도 있습니다.
물론 errno를 사용하는 더 좋은 방법도 있습니다. onlyInt()함수도 보면 아무것도 입력하지 않고 enter를 쳤는지, 아니면 문자가 들어있는 잘못된 입력인지 정상적으로 숫자가 입력되었는지 함수의 리턴 값으로 확인할 수 있지 않습니까? 때문에 반드시 main()함수는 정수형 리턴 값을 가져야 합니다. 간혹 void main()함수를 작성하기도 하지만 그것은 좋지 않은 습관입니다. void를 쓸 바에야 차라리 생략하는 것이 나을 듯 합니다. 그러면 int가 생략된 것으로 인식할 것 입니다.


   

OS에서 사용하는 error 번호 확인하기  


#include <stdio.h>

#include <string.h>  

/*

* copyleft (l) 2006 - 2017 programmed by Sinclair

*/   

int main() {

    int error ;  

    for( error = 0 ; error < 256 ; error++ ){

        printf("%d: %s\n" , error , strerror(error) ) ;

        // stderror() error번호의 해당 메시지 문자열의 주소를 return

    } // end for

    return 0 ;  

} // end main()    




main()함수도 부를 수 있다?  


에이 main() 함수를 어떻게 불러요? 라고 생각하는 분들이 있겠지만. main()도 함수 입니다. 함수는 그의 이름을 불러 주면 내게로 와서 꽃이 됩니다. 그렇다면 main()함수는 어떻게 부릅니까? 일반 함수랑 동일하게 부릅니다. main()아~ 운전해~ 어~~서~!  



main() {

    /* do something */

} // 이런 함수라면  


main() ; // 이라고 부릅니다.  



main(int argc , char ** argv) {

    /* do something */

} // 요런 함수라면  


main( 0 , NULL ) ; // 또는  

char * sinclair[] = { "Sinclair", NULL } ;

main(1 , sinclair) ; // 이렇게 부르면 됩니다.  



이렇게 일반 함수 호출하듯이 직접 부르는 방법이 있는가 하면 OS로 하여금 부르게 하는 방법이 있습니다. <stdlib.h>에 있는 system()함수를 사용하는 방법입니다. system()함수는 shell을 불러서 지정프로그램을 실행하고 다시 돌아오는 함수입니다.  


system("부르고싶은메인함수가있는프로그램명") ;

system("부르고싶은메인함수가있는프로그램명   필요한인자(들)") ;  


이렇게 호출하면 main()함수를 부를 수 있게 됩니다.

특히 main()함수를 호출할 때는 무한 재귀 호출이 되지 않도록 주의해야 합니다.

main() 안에서 자신을 부르고 그 자신이 또 자신을 부르고 이렇게 계속하다 보면 선언된 지역변수들이 스택에 계속 쌓이게 되겠죠? 결국 그러면 메모리가 부족해지게 됩니다. 스택에 대한 부분은 미리 자료 구조나 컴퓨터 구조 책들을 통해서 자세히 공부해야 나중에 후회하지 않습니다. 지금 당장 공부하세요!






#Sinclair #씽클레어 #싱클레어 #씽클레어도씨 #씨언어 #씨프로그래밍  #C언어 #Cprogramming #C_Programming #C #Programming #Clanguage #C_Language

매거진의 이전글 함수와 함수의 활용
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari