C에서 "함수에 대한 충돌 유형"을 얻을 수 있습니다. 이유는 무엇입니까?
다음 코드를 사용하고 있습니다.
char dest[5];
char src[5] = "test";
printf("String: %s\n", do_something(dest, src));
char *do_something(char *dest, const char *src)
{
return dest;
}
「 」의 do_something
두 가지 예외가 합니다.위의 내용을 컴파일하려고 하면 다음 두 가지 예외가 발생합니다.
'do_something' : 'do_something' 입니다.
오류: 'do_something'의 이전 암묵적 선언이 여기에 있습니다(프로토타입 라인).
왜요?
선언하기 전에 do_something을 호출하려고 합니다.printf 라인 전에 함수 프로토타입을 추가해야 합니다.
char* do_something(char*, const char*);
또는 함수 정의를 printf 행 위로 이동해야 합니다.함수를 선언하기 전에 사용할 수 없습니다.
A C 함수 선언 배경화면
C에서 함수 선언은 다른 언어에서처럼 작동하지 않습니다.C 컴파일러 자체는 호출한 위치에서 함수의 선언을 찾기 위해 파일을 앞뒤로 검색하지 않습니다.또한 관계를 파악하기 위해 여러 번 파일을 스캔하지 않습니다.컴파일러는 파일을 위에서 아래로 한 번만 앞으로 스캔합니다.함수 호출을 함수 선언에 연결하는 것은 링커 작업의 일부이며 파일이 원시 어셈블리 명령으로 컴파일된 후에만 수행됩니다.
즉, 컴파일러가 파일을 스캔할 때 함수의 이름을 처음 접했을 때 다음 두 가지 중 하나가 해당되어야 합니다.함수 선언 자체를 보고 있습니다.이 경우 컴파일러는 함수가 무엇인지, 어떤 유형을 인수로 사용하고, 어떤 유형을 반환하는지 정확하게 알고 있습니다.또는 함수에 대한 호출이며, 컴파일러는 함수가 최종적으로 어떻게 선언되는지를 추측해야 합니다.
(세 번째 옵션은 기능 프로토타입에 이름이 사용되는 것입니다만, 우선 이 문제가 발견되면 프로토타입을 사용하지 않을 가능성이 높기 때문에 일단 무시하겠습니다.)
역사 수업
C의 초창기에는 컴파일러가 유형을 추측해야 한다는 사실은 문제가 되지 않았습니다.모든 타입이 거의 같거나 비슷했습니다.거의 모든 것이 int 또는 포인터이며, 같은 크기였습니다.(실제로 C보다 앞의 언어인 B에서는 타입이 전혀 없고, 모든 것이 int 또는 포인터일 뿐이며, 타입은 사용법에 의해서만 결정되었습니다!)따라서 컴파일러는 전달된 파라미터의 수만을 기반으로 함수의 동작을 안전하게 추측할 수 있습니다.2개의 파라미터를 넘겼을 경우 컴파일러는 콜스택에2개의 것을 푸시하고, 아마 착신측에는2개의 인수가 선언되어 모두 라인업 됩니다.1개의 파라미터만 전달했는데 함수가 2를 예상했을 경우, 이 파라미터는 여전히 소트 동작하며, 두 번째 인수는 무시되거나 낭비됩니다.세 개의 매개 변수를 전달하고 두 개의 매개 변수를 예상한 함수도 여전히 정렬 작업을 수행하며, 세 번째 매개 변수는 함수의 로컬 변수에 의해 무시되고 짓밟힙니다.(일부 오래된 C코드에서는 이들 미스매치 인수의 규칙도 동작할 것으로 예상하고 있습니다).
그러나 컴파일러를 통해 어떤 것이든 전달할 수 있는 것은 프로그래밍 언어를 설계하는 데 좋은 방법이 아닙니다. 유형을을 알고 C프로그래머, C프로그래머와 같은 .lint
C 코드를 더 자세히 확인하고 경고할 수 있습니다.
오늘로 거슬러 올라가면, 우리는 완전히 같은 처지가 아닙니다.이 프로그래밍을 으로 C를 사용한 모든 ).lint
에 어든 of of of of of of of of of of of of of that of of of that that의 일부였던 많은 능력을 .lint
하여 타입이 - 코드 체크는 안전합니다 C 에서는 "C"라고 쓸 수 .int foo = "hello";
그냥 가볍게 포인터를 정수에 할당하고, 멍청한 짓은 하지 않는 게 네 책임이야.최신 C 컴파일러는 타입이 틀리면 큰 소리로 불평합니다.그것은 좋은 일입니다.
유형 충돌
그러면 이 모든 것이 함수 선언 줄에 있는 알 수 없는 충돌 유형의 오류와 무슨 관련이 있을까요?위에서 설명한 바와 같이 C 컴파일러는 파일을 스캔할 때 이름을 처음 봤을 때 그 의미를 파악하거나 추측해야 합니다.실제 함수 선언 자체(또는 "프로토타입" 함수 등)라면 그 의미를 알 수 있지만, 함수에 대한 호출일 경우 추측해야 합니다.그리고, 슬프게도, 추측은 종종 틀립니다.
의 했을 때do_something()
발동되었는지를 결과, '발동하다', '하다'라는 결론을 내렸습니다.do_something()
최종적으로는 다음과 같이 선언됩니다.
int do_something(char arg1[], char arg2[])
{
...
}
왜 그렇게 결론을 내렸을까요?그렇게 불렀기 때문에! (C 컴파일러에 따라서는 다음과 같은 결론을 내릴 수 있습니다.int do_something(int arg1, int arg2)
단순히 「」라고 하는 것.int do_something(...)
둘 다 원하는 것과는 거리가 멀지만 중요한 점은 컴파일러가 유형을 어떻게 추측하든 실제 기능과는 다르게 추측한다는 것입니다.
나중에 컴파일러가 파일을 스캔할 때 실제 선언이 표시됩니다.char *do_something(char *, char *)
이 함수의 선언은 컴파일러가 추측한 선언에 가깝지도 않습니다.이것은 컴파일러가 콜을 컴파일한 행이 잘못되어 프로그램이 동작하지 않는 것을 의미합니다.따라서 코드가 기술된 대로 작동하지 않는다는 오류를 올바르게 출력할 수 있습니다.
여러분은 궁금하실지도 모릅니다. "왜 내가 이 사진을 돌려준다고 가정하는 거지?"int
그 반대되는 정보가 없기 때문에 그런 유형으로 추정됩니다.printf()
변수 인수의 모든 유형을 받아들일 수 있기 때문에 더 나은 답이 없으면int
(많은 얼리 C 컴파일러들은 항상 이 모든 것들을int
특정되지 않은 모든 유형에 대해, 그리고 그 의미는...
선언된 모든 함수의 인수에 대해f()
- 없음void
- 그렇기 때문에 많은 최신 코드 표준이 항상 다음과 같이 사용할 것을 권장합니다.void
논쟁의 대상이 될 수 없습니다.)
더 픽스
함수 선언 오류에는 두 가지 일반적인 수정이 있습니다.
첫 번째 솔루션은 다른 많은 답변에서 권장하는 것으로 함수가 처음 호출된 위치 위의 소스 코드에 프로토타입을 넣는 것입니다.프로토타입은 함수의 선언과 비슷하지만 본문에는 세미콜론이 있습니다.
char *do_something(char *dest, const char *src);
프로토타입을 우선시함으로써 컴파일러는 최종적으로 함수가 어떻게 보일지 알 수 있으므로 추측할 필요가 없습니다.관례상 프로그래머는 파일 맨 위에 프로토타입을 넣는 경우가 많습니다.#include
스테이트먼트의 잠재적인 사용 전에 항상 정의되도록 합니다.
또 다른 솔루션은 실제 코드에도 나타나지만 단순히 함수를 재정렬하여 함수 선언이 항상 함수 선언을 호출하는 것 앞에 오도록 하는 것입니다.전체를 이동할 수 있습니다.char *do_something(char *dest, const char *src) { ... }
이 경우 컴파일러는 함수가 어떻게 생겼는지 정확하게 알 수 있으므로 추측할 필요가 없습니다.
실제로 대부분의 사람들은 기능 프로토타입을 사용합니다. 기능 프로토타입을 가져다가 헤더로 이동할 수도 있기 때문입니다..h
)를 파일화하여 다른 코드로 만듭니다..c
파일은 이러한 함수를 호출할 수 있습니다.그러나 어느 쪽의 솔루션도 효과가 있어, 많은 코드 베이스가 양쪽 모두를 사용하고 있습니다.
C99 및 C11
새로운 버전의 C 표준에서는 규칙이 약간 다르다는 점에 주의해 주십시오.이전 버전(C89 및 K&R)에서는 컴파일러는 함수 호출 시 유형을 추측할 수 있었습니다(그리고 K&R 시대의 컴파일러는 오류가 발생해도 경고조차 하지 않습니다).C99와 C11은 모두 첫 번째 콜 앞에 함수 선언/프로토타입이 있어야 합니다.그렇지 않으면 에러가 됩니다.그러나 대부분의 최신 C 컴파일러는 (주로 이전 코드와의 하위 호환성을 위해) 프로토타입이 부족하다는 경고만 하고 오류로 간주하지 않습니다.
「classic」C 언어(C89/90)에서는, 선언되지 않은 함수를 호출하면, C는, 다음의 값을 반환하는 것을 전제로 합니다.int
또한 실제 인수 유형에서 파라미터 유형을 도출하려고 시도합니다(전에도 누군가가 제안했듯이 파라미터가 없다고 가정하지 않습니다).
구체적인 예에서는 컴파일러는 다음 항목을 참조합니다.do_something(dest, src)
호출하여 암묵적으로 선언을 도출하다do_something
후자는 다음과 같습니다.
int do_something(char *, char *)
단, 코드 후반부에서 명시적으로 선언하는 경우do_something
~하듯이
char *do_something(char *, const char *)
보시다시피 이 선언들은 서로 다릅니다.이것은 컴파일러가 싫어하는 것입니다.
다시 보기:
char dest[5];
char src[5] = "test";
printf("String: %s\n", do_something(dest, src));
이 행에 초점을 맞춥니다.
printf("String: %s\n", do_something(dest, src));
do_something 함수가 선언되지 않았음을 알 수 있습니다!
조금만 더 보시면
printf("String: %s\n", do_something(dest, src));
char *do_something(char *dest, const char *src)
{
return dest;
}
사용 후 기능을 선언하는 것을 알 수 있습니다.
다음 코드를 사용하여 이 부품을 수정해야 합니다.
char *do_something(char *dest, const char *src)
{
return dest;
}
printf("String: %s\n", do_something(dest, src));
건배;)
사용하기 전에 신고하지 않으셨잖아요.
이런 게 필요하잖아요
char *do_something(char *, const char *);
printf 전에.
예:
#include <stdio.h>
char *do_something(char *, const char *);
char dest[5];
char src[5] = "test";
int main ()
{
printf("String: %s\n", do_something(dest, src));
return 0;
}
char *do_something(char *dest, const char *src)
{
return dest;
}
또는 전체를 넣을 수도 있습니다.do_something
기능을 합니다.
이 문제는 c 함수 정의를 변경하여 대응하는 헤더 정의를 업데이트하지 않은 경우에 자주 발생합니다.
함수를 사용하기 전에 프로토타입을 제공하지 않으면 C는 임의의 수의 파라미터를 사용하고 int를 반환한다고 가정합니다.따라서 처음에 do_something을 사용하려고 할 때 컴파일러가 찾고 있는 함수가 바로 그것입니다.이렇게 하면 "암묵적인 함수 선언"에 대한 경고가 생성됩니다.
따라서 나중에 실제로 함수를 선언할 때 C는 함수 오버로드를 허용하지 않습니다. 따라서 C는 서로 다른 프로토타입으로 동일한 이름으로 두 함수를 선언했기 때문에 짜증납니다.
간단한 답변: 함수를 사용하기 전에 선언합니다.
C계명 #3:
K&R #3 Thou shalt always prototype your functions or else the C compiler will extract vengence.
http://www.ee.ryerson.ca:8080/~elf/hack/God.vs.K+R.html
사용하기 전에 기능을 선언해야 합니다.선언 전에 함수 이름이 나타나면 C 컴파일러는 특정 규칙을 따르고 선언 자체를 수행합니다.틀리면 그 오류가 발생합니다.
두 가지 옵션이 있습니다. (1) 사용하기 전에 정의하거나 (2) 구현하지 않고 순방향 선언을 사용합니다.예를 들어 다음과 같습니다.
char *do_something(char *dest, const char *src);
마지막에 세미콜론을 적어 둡니다.
함수 선언의 유형이 먼저 선언되었는지 확인하십시오.
/* start of the header file */
struct intr_frame{...}; //must be first!
void kill (struct intr_frame *);
/* end of the header file */
#arpa/inet <arpa/inet.h>
objective-c 'inet_ntoa'에 대해 충돌하는 유형
언급URL : https://stackoverflow.com/questions/1549631/getting-conflicting-types-for-function-in-c-why
'programing' 카테고리의 다른 글
파이 차트가 완전히 렌더링되지 않음 (0) | 2022.07.08 |
---|---|
POSIX 스레드 및 신호 (0) | 2022.07.08 |
ThreadLocal 변수를 언제 어떻게 사용해야 합니까? (0) | 2022.07.08 |
링크 리스트에서 루프를 검출하려면 어떻게 해야 합니다. (0) | 2022.07.08 |
std::ios_base:에 대한 정의되지 않은 참조:초기화::Init()' (0) | 2022.07.08 |