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'에 대한 유형 충돌 (printf 호출시)
오류 : 'do_something'의 이전 암시 적 선언이 여기에 있습니다 (프로토 타입 줄에 있음).
왜?
선언하기 전에 do_something을 호출하려고합니다. printf 줄 앞에 함수 프로토 타입을 추가해야합니다.
char* do_something(char*, const char*);
또는 printf 행 위로 함수 정의를 이동해야합니다. 선언되기 전에는 함수를 사용할 수 없습니다.
"클래식"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 *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
printf 앞에 전체 함수를 넣을 수 있습니다 .
함수를 사용하기 전에 선언해야합니다. 함수 이름이 선언 전에 나타나면 C 컴파일러는 특정 규칙을 따르고 선언 자체를 만듭니다. 잘못된 경우 해당 오류가 발생합니다.
두 가지 옵션이 있습니다. (1) 사용하기 전에 정의하거나 (2) 구현없이 앞으로 선언을 사용합니다. 예를 들면 :
char *do_something(char *dest, const char *src);
끝에있는 세미콜론에 유의하십시오.
AC 기능 선언 백그 라운더
C에서 함수 선언은 다른 언어 에서처럼 작동하지 않습니다. C 컴파일러 자체는 호출 한 위치에서 함수 선언을 찾기 위해 파일에서 앞뒤로 검색하지 않으며 파일을 스캔하지 않습니다. 관계를 파악하기 위해 여러 번 다음 중 하나를 수행합니다. 컴파일러 는 파일 에서 위에서 아래로 정확히 한 번만 앞으로 스캔 합니다 . 함수 호출을 함수 선언에 연결하는 것은 링커 작업의 일부이며 파일이 원시 어셈블리 명령어로 컴파일 된 후에 만 수행됩니다 .
즉, 컴파일러가 파일을 통해 앞으로 스캔 할 때 컴파일러가 함수 이름을 처음 발견 할 때 다음 두 가지 중 하나가 해당되어야합니다. 함수 선언 자체를보고 컴파일러가 알고있는 경우 정확히 함수가 무엇인지, 인수로 취하는 유형과 반환하는 유형이 무엇인지, 아니면 함수에 대한 호출이고 컴파일러는 함수가 결국 어떻게 선언 될지 추측해야 합니다.
(함수 프로토 타입에서 이름이 사용되는 세 번째 옵션이 있지만, 처음에이 문제가 발생하면 프로토 타입을 사용하지 않을 것이므로 지금은 무시하겠습니다.)
역사 수업
C의 초창기에는 컴파일러가 유형을 추측해야한다는 사실이 실제로 문제가되지 않았습니다. 모든 유형이 거의 동일했습니다. 거의 모든 것이 int 또는 포인터였습니다. 같은 크기. (사실, C 이전의 언어 인 B에서는 유형이 전혀 없었습니다. 모든 것이 정수 또는 포인터 였고 그 유형은 사용 방법에 의해서만 결정되었습니다!) 따라서 컴파일러는 모든 유형의 동작을 안전하게 추측 할 수 있습니다. 전달 된 매개 변수의 수를 기반으로하는 함수 : 두 개의 매개 변수를 전달하면 컴파일러는 두 가지를 호출 스택에 푸시하고 아마도 호출 수신자는 두 개의 인수를 선언하고 모두 정렬됩니다. 매개 변수를 하나만 전달했지만 함수가 두 개를 예상 한 경우에는 여전히 작동하고 두 번째 인수는 무시되거나 가비지됩니다. 세 개의 매개 변수를 전달하고 함수가 두 개를 예상 한 경우에도 여전히 작동하며 세 번째 매개 변수는 무시되고 함수의 지역 변수에 의해 밟 히게됩니다. (일부 오래된 C 코드는 여전히 이러한 불일치 인수 규칙도 작동 할 것으로 예상합니다.)
그러나 컴파일러를 사용하여 무엇이든 전달할 수 있다는 것은 프로그래밍 언어를 설계하는 좋은 방법이 아닙니다. 초기 C 프로그래머는 대부분 마법사 였고, 잘못된 유형을 함수에 전달하지 않는 것을 알고 있었기 때문에 초기에는 잘 작동했습니다. 유형을 잘못 이해 했더라도 lint
더 깊은 이중 검사를 수행 할 수있는 도구가 항상 있었습니다. C 코드에 대해 경고합니다.
오늘로 빨리 감기, 우리는 같은 배에 있지 않습니다. C는 성장했고, 많은 사람들이 마법사가 아닌 프로그래밍을하고 있으며이를 수용하기 위해 (그리고 lint
어쨌든 정기적으로 사용하는 다른 모든 사람들을 수용하기 위해 ) 컴파일러는 이전에 포함되었던 많은 기능을 사용했습니다. lint
-특히 유형이 안전한지 확인하기 위해 코드를 확인하는 부분. 초기 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 *)
. 이 함수 선언은 컴파일러가 추측 한 선언과 비슷하지도 않습니다. 즉, 컴파일러가 호출을 컴파일 한 줄이 잘못 컴파일되었으며 프로그램이 작동하지 않을 것입니다. 따라서 코드가 작성된대로 작동하지 않을 것이라는 오류를 올바르게 인쇄합니다.
You might be wondering, "Why does it assume I'm returning an int
?" Well, it assumes that type because there's no information to the contrary: printf()
can take in any type in its variable arguments, so without a better answer, int
is as good a guess as any. (Many early C compilers always assumed int
for every unspecified type, and assumed you meant ...
for the arguments for every function declared f()
— not void
— which is why many modern code standards recommend always putting void
in for the arguments if there really aren't supposed to be any.)
The Fix
There are two common fixes for the function-declaration error.
The first solution, which is recommended by many other answers here, is to put a prototype in the source code above the place where the function is first called. A prototype looks just like the function's declaration, but it has a semicolon where the body should be:
char *do_something(char *dest, const char *src);
By putting the prototype first, the compiler then knows what the function will eventually look like, so it doesn't have to guess. By convention, programmers often put prototypes at the top of the file, just under the #include
statements, to ensure that they'll always be defined before any potential usages of them.
The other solution, which also shows up in some real-world code, is to simply reorder your functions so that the function declarations are always before anything that calls them! You could move the entire char *do_something(char *dest, const char *src) { ... }
function above the first call to it, and the compiler then would know exactly what the function looks like and wouldn't have to guess.
In practice, most people use function prototypes, because you can also take function prototypes and move them into header (.h
) files so that code in other .c
files can call those functions. But either solution works, and many codebases use both.
C99 and C11
It is useful to note that the rules are slightly different in the newer versions of the C standard. In the earlier versions (C89 and K&R), the compiler really would guess the types at function-call time (and K&R-era compilers often wouldn't even warn you if they were wrong). C99 and C11 both require that the function declaration/prototype must precede the first call, and it's an error if it doesn't. But many modern C compilers — mainly for backward compatibility with earlier code — will only warn about a missing prototype and not consider it an error.
C Commandment #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
When you don't give a prototype for the function before using it, C assumes that it takes any number of parameters and returns an int. So when you first try to use do_something, that's the type of function the compiler is looking for. Doing this should produce a warning about an "implicit function declaration".
So in your case, when you actually do declare the function later on, C doesn't allow function overloading, so it gets pissy because to it you've declared two functions with different prototypes but with the same name.
Short answer: declare the function before trying to use it.
Watch again:
char dest[5];
char src[5] = "test";
printf("String: %s\n", do_something(dest, src));
Focus on this line:
printf("String: %s\n", do_something(dest, src));
You can clearly see that the do_something function is not declared!
If you look a little further,
printf("String: %s\n", do_something(dest, src));
char *do_something(char *dest, const char *src)
{
return dest;
}
you will see that you declare the function after you use it.
You will need to modify this part with this code:
char *do_something(char *dest, const char *src)
{
return dest;
}
printf("String: %s\n", do_something(dest, src));
Cheers ;)
This often happens when you modify a c function definition and forget to update the corresponding header definition.
Make sure that types in the function declaration are declared first.
/* start of the header file */
.
.
.
struct intr_frame{...}; //must be first!
.
.
.
void kill (struct intr_frame *);
.
.
.
/* end of the header file */
참고URL : https://stackoverflow.com/questions/1549631/getting-conflicting-types-for-function-in-c-why
'programing tip' 카테고리의 다른 글
iPhone Simulator : SpringBoard가 오류로 인해 응용 프로그램을 시작하지 못했습니다 : 7 (0) | 2020.11.07 |
---|---|
Java의 Runtime.exec ()를 사용할 때 시간 초과 값을 추가하는 방법은 무엇입니까? (0) | 2020.11.07 |
Microsoft의 데이터베이스 명명 규칙? (0) | 2020.11.07 |
web.xml을 사용하여 Spring에서 컨텍스트로드 (0) | 2020.11.07 |
initWithRootViewController 이외의 메소드로 UINavigationController의 rootViewController 설정 (0) | 2020.11.07 |