보통 C에서 int main으로 선언되고 void main 같은 경우에는 잘못 된 표기라 말해주는데 이 이유가 햇갈린다... 암튼 잘못된 선언인데 그 이유를 알아보자. 보통의 main 선언문 이다. 마지막에 대부분 return 0; 를 선언 해주는데 이 역할은 main() 이 정상적 으로 종료 됨을 의미하는 exit(0) 를 호출한 후, 함수를 종료하게 되는 부분이다. 이는 gcc 로 컴파일 해서 gdb나 이것저것 컴파일을 해보면 볼 수 있는데. sp(stack pointer 맞나?) 에서 main 부분 마지막 줄인 ret을 하면 libc_start_main..(정확히 이름이 기억이 나진 않넹..) 으로 점프하고 exit를 호출 하게 되는것을 확인 할 수 있다. 이때 여기서 exit()의 파라미터인 status 값은 컴파일러 마다 약간 다르게 설정되 있는데 일반적으로 0면 정상종료를 의미한다. 숫자의 의미는 각각의 에러 타입을 의미한다. int main()으로 하지 않고 void main() 으로 한다면 컴파일러가 컴파일 에러를 발생시키지 않아도 프로세스 상에서는 종료조건을 지정해 주지 않았기 때문에 main()함수에서 올바르지 않은 종료조건을 운영체제에 리턴하고 자신을 종료할 가능성이 있게 되어 오류가 생길 수도 있게 된다. 이번 강좌에서는
안녕하세요 여러분. 그동안 잘 지내셨는지요? 책 만드는 것도 어느 정도 진척이 되었고 때로는 우리가 만드는 함수가 리턴값이 없을 수 도 있습니다. 예를 들어서 어떠한 #include <stdio.h> void add_one(int* p) { (*p) += 1; } int main() { int a = 1; printf("Before : %d \n", a); add_one(&a); printf("After : %d \n", a); } 성공적으로 컴파일 하였다면 실행 결과 Before : 1 After : 2 와 같이 나옵니다. 위 void add_one(int* p) { 위와 같이 따라서 다음과 같은 문장은 모두 틀린 셈입니다. void a(); int main() { int i; i = a(); return 0; } void a() {} 즉 함수
int swap(int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp; return 0; } 하지만 void swap(int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp; } 하지만 위와 같이 /* void 형 변수?? */ #include <stdio.h> int main() { void a; a = 3; return 0; } 성공적으로 컴파일 하였다면 컴파일 오류 error C2182: 'a' : 'void' 형식을 잘못 사용했습니다. 와 같은 오류 메세지를 보게 됩니다. 우리가 위에서 int a; 라는 문장을 보게 된다면 컴파일러는 '아, void a; 를 보게 된다면, '응? 이 변수의 타입은 뭐지?' 라고 생각하게 되죠. 다시 말해 이 변수를 위해서 메모리 상에 얼마나 많은 공간을 설정해 놓아야 하는지 모르게 되는 셈입니다. (참고로 컴파일 때 모든 변수들의 메모리 상의 위치가 결정 되어야 합니다) 따라서 이와 같은 형식은 틀리게 된 셈이죠. 그렇다면 이것은 가능할까요? /* void 형을 가리키는 포인터 */ #include <stdio.h> int main() { void* a; return 0; } 성공적으로 컴파일 해 본다면 아무런 오류가 뜨지 않는 다는 것을 알 수 있습니다. 왜 그럴까요? 일단, 그렇다면 void *a; double b = 123.3; a = &b; 와 같이 말이죠. 다시 말해 /* b 의 값을 보려면 */ #include <stdio.h> int main() { void *a; double b = 123.3; a = &b; printf("%lf", *a); return 0; } 성공적으로 컴파일 하였다면 컴파일 오류 error C2100: 간접 참조가 잘못되었습니다. 와 같은 오류를 보게 됩니다. 이 오류가 발생하는 이유 역시 쉽게 알 수 있습니다. 왜냐하면 컴파일러는 #include <stdio.h> int main() { void *a; double b = 123.3; a = &b; printf("%lf", *(double *)a); return 0; } 성공적으로 컴파일 하였다면 실행 결과 123.300000 와 같이 잘 출력됨을 알 수 있습니다. printf("%lf", *(double *)a); 우리는 위 문장에서 형변환 을 이용하였습니다. 즉 단순히 주소값 만을 담고 있는
어떠한 특정한 주소값으로 부터 1 바이트 씩 값을 읽어오는 함수 그렇다면 이 함수는에는 인자가 2 개 전달될 텐데, 일단 그 특정한 주소값을 가리키고 있는 포인터와, 얼마나 읽을지 따라서 우리는 순전히 주소값 만을 받기 위해서는 /* 임의의 주소값 p 로 부터 byte 만큼 읽은 함수*/ #include <stdio.h> int read_char(void *p, int byte); int main() { int arr[1] = {0x12345678}; printf("%x \n", arr[0]); read_char(arr, 4); } int read_char(void *p, int byte) { do { printf("%x \n", *(char *)p); byte--; p = (char *)p + 1; } while (p && byte); return 0; } 성공적으로 컴파일 하였다면 실행 결과 12345678 78 56 34 12
do { printf("%x \n", *(char *)p); byte--; p = (char *)p + 1; } while (p && byte); 먼저 아무튼 이와 같은 방법으로 printf("%x \n", *(char *)p); 는 간단히 말하자면 우리가 쓰는 대부분의 프로세서는 리틀 엔디안 방식으로 저장하기 때문에 낮은 자리수가 낮은 주소값을 가지게 됩니다. 즉, 낮은 자리수인 78 이 낮은 주소값인 앞쪽에 저장되게 되죠. 따라서 12 34 56 78 순이 아닌 78, 56, 34, 12 순으로 저장되는 것이 맞습니다. (그렇게 따지면 87, 65, 43, 21 순으로 나타나야 되지 않냐고 물을 수 있는데 저장의 단위가 바이트 이므로 한 바이트 내에서는 우리가 생각하는 순서대로 저장됩니다. ) /* main 함수의 인자라고?? */ #include <stdio.h> int main(int argc, char **argv) { printf("받은 인자의 개수 : %d \n", argc); printf("이 프로그램의 경로 : %s \n", argv[0]); return 0; } 성공적으로 컴파일 했다면 아마도 이 강좌를 보고 계신 여러분 중 일부는 위와 같은 메인 함수에 친숙하실 지도 모릅니다. int main(int argc, char **argv) 보시다시피 일단 /* 인자를 가지는 메인 함수 */ #include <stdio.h> int main(int argc, char **argv) { int i; printf("받은 인자의 개수 : %d \n", argc); for (i = 0; i < argc; i++) { printf("이 프로그램이 받은 인자 : %s \n", argv[i]); } return 0; } 성공적으로 컴파일 했다면 일단 우리는 프로그램을 임의의 개수의 인자를 받아 받은 인자들을 모두 출력하게 하였습니다. 그렇다면 프로그램에 직접 인자를 넣어 봅시다.
그렇다면 아래와 같은 모습을 보실 수 있습니다. 이것은 '명령 프롬포트' 라고 부르는 것인데 기존의 먼저 위와 같이 화면에 이제 화면에 위와 같은 방식으로 우리의 파일을 찾는 일만 남았습니다. 우리가 원하는 파일은 아마 이제 오. 저의 프로젝트인 'teach' 가 보이네요. 여러분과 저와의 프로젝트 이름이 다를 수 있으니 각기 맞는 프로젝트로 들어가시면 됩니다. 여기서도 물론 폴더 이름에 띄어쓰기가 있다면 큰따옴표로 묶어주는 것을 잊지 마세요. 이제, 파일들을 쭉 보면 우와 그렇다면 위와 같이 우왕. 잘 실행되는 군요. 일단 신기한 점은 이 프로그램이 받은 인자가 더이상 그 프로그램의 경로가 들어가지 않고 만일 우리가 이 프로그램을 그렇다면 다른 인자들을 넣어봅시다. 이는 간단합니다. 프로그램 이름 뒤에 다른 것들을 써주면 되죠. 예를 들어
그런데 여태까지 배운 내용을 잘 숙지하신 분이라면 다음과 같은 질문을 하실 수 있습니다.
그 이유는 간단합니다. 즉, 다음과 같은 꼴이 되겠지요. 즉 따라서 우리는 그럼 이상으로 이번 강좌를 마치도록 하겠습니다. 이번 강좌는 다음에 배울 동적 메모리 할당에 밑바탕이 되는 정보 이니 절대로 잊지 마시기 바랍니다. 메인함수의 인자를 활용한 계산기를 만들어보세요. 예를 들어서 calc.exe 5 + 10 을 치면 15 가 나오게 하면 되지요. 이 때, 강좌를 보다가 조금이라도 궁금한 것이나 이상한 점이 있다면 꼭 댓글을 남겨주시기 바랍니다. 그 외에도 강좌에 관련된 것이라면 어떠한 것도 질문해 주셔도 상관 없습니다. 생각해 볼 문제도 정 모르겠다면 댓글을 달아주세요. 현재 여러분이 보신 강좌는 <씹어먹는 C 언어 - <19. main 함수의 인자, 텅 빈 void 형>> 입니다. 이번 강좌의 모든 예제들의 코드를 보지 않고 짤 수준까지 강좌를 읽어 보시기 전까지 다음 강좌로 넘어가지 말아주세요 |