[C] 선언되지 않은 함수를 호출하는 행위

HDNua의 이미지

오랜만입니다.

C에서는 사용하기 전에 정의되지 않은 함수를 호출하려면, 프로토타입을 사용 전에 먼저 선언해야 합니다.
기본적인 개념이고, 이전까지는 이를 어길 일이 없어서 알아서 잘 사용하고 있었습니다.

다만 요즘 컴퓨터 관련해서 연재하는 글이 있는데, 이를 위해
C에서 먼저 선언되지 않은 함수도 호출이 가능하다는 사실을 적고 싶어져서 문제가 생겼습니다.

예를 들어 Visual Studio 2013과 codepad.org 온라인 컴파일러, ideone 온라인 컴파일러에서 모두 잘 동작하는 C 코드입니다.

#include <stdio.h>
int main() {
    test(1,2,3);
    return 0;
}
test(a,b,c) {
    printf("Hello,world! %d\n", a+b+c);
}

함수의 선언이 없이 호출했기 때문에 문법적으로 옳다고 볼 수는 없는 코드라고 생각하지만, 아무튼 가능합니다.
C의 기본 자료형은 int이고, 반환형이 int이기만 하면 흥미롭게도 인자 정보까지 마음대로 넘길 수 있습니다.

질문.
반환형이 int인 함수를 선언이나 정의 없이 먼저 호출하는 행위는 언제나 타당한지, 이러한 내용이 표준에 명시되어있는지 궁금합니다.
아니면 컴파일러 구현에 따라 다르거나, 그저 정의되지 않은 동작이고 항상 맞는다고 할 수는 없는지가 궁금합니다.

읽어주셔서 감사합니다.

yhsuk의 이미지

표준은 잘 모르겠지만, 아래 링크랑도 관련이 있어 보이는데요.

C FAQ에 있는 링크입니다.
http://www.cinsk.org/cfaqs/html/node3.html#SECTION00390000000000000000 (Q 1.25)

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

HDNua의 이미지

이런 내용이 있네요.
"함수의 선언이, 이 함수를 호출할 때까지 나타나지 않으면, 컴파일러는 이 함수가 int를 리턴한다고 가정합니다."
이 부분이 모든 컴파일러에 대해 참이라면 언제나 옳다고 생각하고 사용할 수 있는 모양이군요.

좋은 답변 감사합니다. 질문 말고도 읽어볼 게 많아보이는 주소네요.

저는 이렇게 생각했습니다.

yhsuk의 이미지

이곳에서도 자주 보셔서 익숙하신 cinsk님 사이트입니다. ^^;
C FAQ 번역자이시도 하시고, 여러 강좌도 쓰시고 저도 참조 많이 하고 있습니다.

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

pchero의 이미지

-Wall 옵션으로 지정시, 컴파일 Warning 으로 나옵니다.

-Wall -Werror 옵션을 사용하게되면 Warning 도 에러로 간주하게 되는데, 이런 자잘한 오류들을 잡아내는데 좋습니다.

---------------------------------
제일 왼쪽이 저입니다 :)

HDNua의 이미지

팁 잘 받았습니다. 감사합니다.

저는 이렇게 생각했습니다.

klyx의 이미지

오래된 C에서는 표준에서 보장하는 일이지만 절대 추천하지 않는 방법이고, C++에서는 금지되어있습니다.
C99부터는 금지되었지만 하위호환을 위해서 컴파일러가 엄격하게 적용하지 않기도 합니다.
implicit int rule이나 implicit declaration of function 이라고 찾아보시면 더 많은 정보가 나올겁니다.

이 때문에 다음과 같이 잘 컴파일되고 일반적으로 x86에서는 문제없어보이는 코드가 x86_64에서는 죽어버리는 코드가 나타날 수 있습니다.

int main() {
   int *p = malloc(sizeof(int));
   *p = 1;
   return 0;
}

> C의 기본 자료형은 int이고, 반환형이 int이기만 하면 흥미롭게도 인자 정보까지 마음대로 넘길 수 있습니다.

이부분은 링커와 관련되어있는데, 원래 C던 C++이던 함수를 호출할때 인자의 갯수나 타입과 같은 인자에 대한 정보는 안넘어갑니다.
호출하는 쪽에서는 호출할 함수의 주소와 함께 그냥 인자를 스택(또는 레지스터)에 넣어주면, 호출받은 함수쪽에서 알아서 호출규약에 맞게 값들을 끌어다 쓰는 것입니다.
함수 주소는 링커에 의해서 심볼명으로부터 resolve되는데, 이때 C는 함수의 이름이 거의 그대로 심볼명이됩니다.
그렇기 때문에 C에서는

int test();
int test(int a);
int test(int a, int b);

와 같이 서로 다른 인자로 같은 이름의 함수 원형을 선언해도 호출하는 함수는 모두 같습니다.
물론 같은 파일에서 서로 다른 원형을 선언하는건 불가능하지만 서로 다른 파일에서 각자 원형을 선언하는 건 가능합니다.
다만 가능하다고 해서 써도 되는건 당연히 아니고, 주는 인자가 받는 인자보다 많으면 (순서만 타입과 잘 맞으면) 문제가 안될 수도 있지만,
반대로 주는 인자가 받는 인자보다 적으면 당연히 스택이 깨지고 프로그램은 정의되지 않은 동작에 빠집니다.

C++의 경우에는 이런 경우 함수 오버로딩을 하기위해서 name mangling을 해서 컴파일러가 함수 이름(심볼) 자체를 바꿔버리기 때문에 문제가 되지않습니다.

HDNua의 이미지

사실 이런 질문을 할 때 어떤 키워드로 검색해야 좋을지 몰라 올린 질문이기도 했는데,
키워드를 딱 제시를 해주시는군요. C99부터 금지되었다니 후에 작성할 문서에 이 내용을 꼭 강조해야겠네요.

소중한 답변 감사합니다.

저는 이렇게 생각했습니다.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.