그냥저냥

문제풀이 | The C Programming Language (K&R): Exercise 1-1 본문

개발기/The C Programming Language

문제풀이 | The C Programming Language (K&R): Exercise 1-1

sync86 2026. 4. 25. 14:04
728x90
반응형

책: The C Programming Language (K&R)

본문의 연습문제는 저작권 이슈로 그 내용을 직접적으로 언급하지 않습니다. 이점 양해 바랍니다.

처음에 아무 생각없이 이 책을 펼쳤는데, The C Programming Language Exercise 1-1을 보며 생각보다 봐야할 게 많다는 사실에 깜짝 놀랐는데, 어떤 내용을 확인해야 하는지 간단하게 정리를 해보았습니다.

Exercise 1-1 풀기전에 확인해야 할 것!

이 책의 초판 발행 년도,

1978년, 제가 가지고 있는 것은 1988년 개정된 2판인데,

초판 발행년도를 감안하면 이 문제는 본인의 시스템에서 "hello, world" 소스코드를 작성하고 컴파일할 수 있는 환경을 직접 구성해보라는 주문에 더 가까운 것 같아요.

 

왠지 그런 느낌이 듭니다.

 

당시에는 컴파일러가 이 책의 저자들이 만든 컴파일러가 전부였던 것 같습니다.

책 내용 중에 컴파일러 설치하는 방법에 대해서는 다루지 않고 있습니다.

그런 의미에서 확실히 최근 출간된 책에 비해 불친절하다는 생각이 드네요.

$ cc hello.c

 

현재는 MSVC, gcc, clang 등 많은 컴파일러가 나와 있습니다.

그래서 이러한 컴파일러를 직접 설치하고 구성할 수 있어야 할 것 같습니다.

설명은 생략하겠지만, 구글에 "OOO에서 OOO 설치 방법", "OOO에서 OOO 컴파일 방법"이라고 검색하면 다 나옵니다.

 

위와 같이 명령어를 실행하고 컴파일이 정상적으로 잘 되었다면 아래와 같이 a.out 파일이 생성되는데, 이 파일명을 바꿀 수 있습니다.

여기서는 꼭 사용하고 계시는 컴파일러 메뉴얼을 확인해야 해요.

$ ls
a.out hello.c

 

사실 아래와 같이 -o (소문자) 옵션을 사용하여 원하는 출력되는 파일명을 작성하면 됩니다.

물론 출력되는 파일명 옵션에 대해서 알려드렸습니다.

다만, 책에서는 이 옵션에 대해 언급이 없었습니다.

그래서 이 옵션을 사용하지 않는다고 가정하겠습니다.

$ cc -o hello ./hello.c

C언어의 표준. C89 -> C99 이후 - 최신 표준은 C23 (ISO/IEC 9899:2024)

 최근 컴파일러에서 컴파일할 때 오류가 생길 여지가 많아집니다.

 

책에서 소스코드는 무심하게 아래와 같이 되어 있는데, 최근 컴파일러가 C99 표준 이상을 지원하는 경우가 많습니다.

따라서 아래와 같이 작성하면 컴파일러가 투덜되거나 컴파일을 거절할 수 있다는 점 유의해야 합니다.

#include <stdio.h>

main()
{
    printf("hello, world\n");
}

 

아래와 같이 변경하는게 좋을 것 같습니다.

#include <stdio.h>

int main(void)
{
    printf("hello, world\n");
    return 0;
}

 

 아니면 아래의 스타일로 해야 합니다. 개인적으로 가장 선호하는 스타일입니다.

#include <stdio.h>

int main(int argc, char** argv)
{
    printf("hello, world\n");
    return 0;
}

 

main() 함수의 파라미터를 사용하지 않을 거면, 아래와 같은 가이드를 제공하는 곳도 있었습니다.

#include <stdio.h>

int main(int /*argc*/, char** /*argv*/)
{
    printf("hello, world\n");
    return 0;
}

 

다만, 제가 테스트 했을 때 결과는 아래의 표와 같습니다.

 

구분 내용
gcc 경고, 오류 없음
clang 경고 (아래 코드 블록 참고)

 

$ cc --version
Ubuntu clang version 18.1.3 (1ubuntu1)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
$ cc ./hello.c
hello.c:4:24: warning: omitting the parameter name in a function definition is a C23 extension [-Wc23-extensions]
    4 | int main(int /* argc */, char** /* argv */)
      |                        ^
hello.c:4:43: warning: omitting the parameter name in a function definition is a C23 extension [-Wc23-extensions]
    4 | int main(int /* argc */, char** /* argv */)
      |                                           ^
2 warnings generated.

 

과거 오픈소스 코드를 보다가 아래와 같은 코드를 봤던 기억이 있습니다.

gcc에서는 문제가 없을 것으로 보이지만, clang에서는 역시 유사하게 경고를 확인하였습니다.

#include <stdio.h>

int main(argc, argv)
    int argc;
    char** argv;
{
    printf("hello, world\n");
    return 0;
}
$ cc --version
Ubuntu clang version 18.1.3 (1ubuntu1)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
$ cc ./hello.c
./hello.c:4:5: warning: a function definition without a prototype is deprecated in all versions of C and is not supported in C23 [-Wdeprecated-non-prototype]
    4 | int main(argc, argv)
      |     ^
1 warning generated.

C언어 표준에 따른 main() 함수 변천

구분 K&R 스타일 (1978/1988) 현대적 스타일 (C99~C23)
반환 타입 main() (암묵적으로 int형 반환) int main(void) (명시적)
파라미터 main(argc, argv) {} int main(int argc, char** argv) {}
반환값 생략 가능 (Undefined) return 0; (성공 반환 명시)

경고와 에러 메시지의 차이

컴파일러를 사용하여 컴파일할 때 종종 경고나 에러 메시지를 볼 수 있습니다.

차이는 아래의 표와 같습니다.

 

구분 설명
경고 경고 메시지만 출력되고, 컴파일은 진행됩니다. 다만, 경우에 따라서는 프로그램이 실행 중 의도하지 않는 동작을 하거나 중단될 수 있습니다.
에러 에러 메시지 출력되며 컴파일은 중단됩니다. 결과 파일인 a.out 파일이 만들어지지 않으므로 반드시 수정해야 합니다.

반환값 용도

아마도 main() 함수에서 반환값은 위에 작성한 코드와 같이 묻지도 따지지도 않고 return 0; 코드를 작성했을 겁니다.

 

하지만, 이 반환값 용도는 운영체제에서 어플리케이션 종료한 상태를 확인을 위한 용도이죠.

 

컴파일이 정상적으로 실행되고, 결과물을 실행한 후 쉘에서 아래와 명령어로 확인할 수 있습니다.

참고로 이 명령어 실행 결과에 해당되는 소스코드 및 컴파일 방법은 설명하지 않는데, 위에서 언급했으니 넘어가겠습니다.

$ ./a.out
$ echo $?
0

 

위의 결과는 당연히 return 0;에 해당되는 결과이구요. 만약에 return 1;로 했다면 echo $?의 결과는 1이 나올겁니다.

#include <stdio.h>

int main(int argc, char** argv)
{
	printf("hello, world\n");
	return -1;
}

 

그렇다면 return -1;로 수정하고 echo $? 명령을 실행하면 어떤 결과를 내줄까요?

$ ./a.out
$ echo $?
255

 

즉, 쉘에서 나타낼 수 있는 값의 범위는 0~255임을 확인할 수 있습니다.

근데 왜? 255까지일까요?

이 부분은 이번 내용에서 벗어난다고 생각해서 제외하겠습니다.

더 파야 하지만, 이번 포스팅에 내용에서 벗어나는 것 같습니다.

Exercise 1-1 두번째, 요구사항

망가뜨려라.

의도적으로 코드를 망가뜨렸들 때, 어떤 오류가 나오는지 확인해봐야 합니다.

 

첵에서는 아래와 같은 코드만 나오는 것 같습니다.

#include <stdio.h>

main()
{
    printf("hello, world\n
    ");
}

 

위의 코드는 책에서 소개된 코드이고, 실제로 코드는 아래와 같이 작성하였습니다.

#include <stdio.h>

int main(int argc, char** argv)
{
    printf("hello, world\n
    ");
    return 0;
}

 

이후 빌드와 컴파일, 2개의 경고, 2개의 에러로 실패하였습니다.

일단은 쌍따옴표 사이에 줄바꿈은 허용되지 않는다 정도로만 확이하면 될 것 같습니다.

$ cc --version
Ubuntu clang version 18.1.3 (1ubuntu1)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
$ cc ./hello.c
./hello.c:5:12: warning: missing terminating '"' character [-Winvalid-pp-token]
    5 |     printf("hello, world\n
      |            ^
./hello.c:5:12: error: expected expression
./hello.c:6:5: warning: missing terminating '"' character [-Winvalid-pp-token]
    6 |     ");
      |     ^
./hello.c:8:2: error: expected '}'
    8 | }
      |  ^
./hello.c:4:1: note: to match this '{'
    4 | {
      | ^
2 warnings and 2 errors generated.

마무리

과거 사회 초년생 때, C언어로 프로젝트 경험한 이력이 있습니다.

다만, 옛날에 봤다면 몰랐을 내용인데, 경력이 쌓이다 보니 기존에 보이지 않았던 부분들이 보이기 시작하네요.
다음은 "The C Programming Language: Exercise 1-2" 문제 풀어보겠습니다.

 

728x90
반응형