在 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的实现在这里并不重要。 当我尝试编译以上内容时,我得到了以下两个例外:

Error: ‘ do _ something’的冲突类型(在 printf 调用时)
Error: 之前隐式声明的‘ do _ something’在这里(在原型行)

为什么?

344951 次浏览

You didn't declare it before you used it.

You need something like

char *do_something(char *, const char *);

before the printf.

Example:

#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;
}

Alternatively, you can put the whole do_something function before the printf.

You are trying to call do_something before you declare it. You need to add a function prototype before your printf line:

char* do_something(char*, const char*);

Or you need to move the function definition above the printf line. You can't use a function before it is declared.

You have to declare the function before you use it. If the function name appears before its declaration, C compiler will follow certain rules and makes the declaration itself. If it is wrong, you will get that error.

You have two options: (1) define it before you use it, or (2) use forward declaration without implementation. For example:

char *do_something(char *dest, const char *src);

Note the semicolon at the end.

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.

In "classic" C language (C89/90) when you call an undeclared function, C assumes that it returns an int and also attempts to derive the types of its parameters from the types of the actual arguments (no, it doesn't assume that it has no parameters, as someone suggested before).

In your specific example the compiler would look at do_something(dest, src) call and implicitly derive a declaration for do_something. The latter would look as follows

int do_something(char *, char *)

However, later in the code you explicitly declare do_something as

char *do_something(char *, const char *)

As you can see, these declarations are different from each other. This is what the compiler doesn't like.

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

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 */

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.

A C Function-Declaration Backgrounder

In C, function declarations don't work like they do in other languages: The C compiler itself doesn't search backward and forward in the file to find the function's declaration from the place you call it, and it doesn't scan the file multiple times to figure out the relationships either: The compiler only scans forward in the file exactly once, from top to bottom. Connecting function calls to function declarations is part of the linker's job, and is only done after the file is compiled down to raw assembly instructions.

This means that as the compiler scans forward through the file, the very first time the compiler encounters the name of a function, one of two things have to be the case: It either is seeing the function declaration itself, in which case the compiler knows exactly what the function is and what types it takes as arguments and what types it returns — or it's a call to the function, and the compiler has to guess how the function will eventually be declared.

(There's a third option, where the name is used in a function prototype, but we'll ignore that for now, since if you're seeing this problem in the first place, you're probably not using prototypes.)

History Lesson

In the earliest days of C, the fact that the compiler had to guess types wasn't really an issue: All of the types were more-or-less the same — pretty much everything was either an int or a pointer, and they were the same size. (In fact, in B, the language that preceded C, there were no types at all; everything was just an int or pointer and its type was determined solely by how you used it!) So the compiler could safely guess the behavior of any function just based on the number of parameters that were passed: If you passed two parameters, the compiler would push two things onto the call stack, and presumably the callee would have two arguments declared, and that would all line up. If you passed only one parameter but the function expected two, it would still sort-of work, and the second argument would just be ignored/garbage. If you passed three parameters and the function expected two, it would also still sort-of work, and the third parameter would be ignored and stomped on by the function's local variables. (Some old C code still expects these mismatched-argument rules will work, too.)

But having the compiler let you pass anything to anything isn't really a good way to design a programming language. It worked well in the early days because the early C programmers were mostly wizards, and they knew not to pass the wrong type to functions, and even if they did get the types wrong, there were always tools like lint that could do deeper double-checking of your C code and warn you about such things.

Fast-forward to today, and we're not quite in the same boat. C has grown up, and a lot of people are programming in it who aren't wizards, and to accommodate them (and to accommodate everyone else who regularly used lint anyway), the compilers have taken on many of the abilities that were previously part of lint — especially the part where they check your code to ensure it's type-safe. Early C compilers would let you write int foo = "hello"; and it would just blithely assign the pointer to the integer, and it was up to you to make sure you weren't doing anything stupid. Modern C compilers complain loudly when you get your types wrong, and that's a good thing.

Type Conflicts

So what's all this got to do with the mysterious conflicting-type error on the line of the function declaration? As I said above, C compilers still have to either know or guess what a name means the first time they see that name as they scan forward through the file: They can know what it means it if it's an actual function declaration itself (or a function "prototype," more on that shortly), but if it's just a call to the function, they have to guess. And, sadly, the guess is often wrong.

When the compiler saw your call to do_something(), it looked at how it was invoked, and it concluded that do_something() would eventually be declared like this:

int do_something(char arg1[], char arg2[])
{
...
}

Why did it conclude that? Because that's how you called it! (Some C compilers may conclude that it was int do_something(int arg1, int arg2), or simply int do_something(...), both of which are even farther from what you want, but the important point is that regardless of how the compiler guesses the types, it guesses them differently from what your actual function uses.)

Later on, as the compiler scans forward in the file, it sees your actual declaration of char *do_something(char *, char *). That function declaration isn't even close to the declaration that the compiler guessed, which means that the line where the compiler compiled the call was compiled wrong, and the program is just not going to work. So it rightly prints an error telling you that your code isn't going to work as written.

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.

#include <arpa/inet.h>

for objective-c Conflicting types for 'inet_ntoa'