开发者

In C, how come function may have several declarations but only one definition?

开发者 https://www.devze.com 2023-03-17 01:03 出处:网络
In C, how come a function may have several declarations but only one 开发者_开发问答definition?Can someone elaborate on that please!In order to allow multiple definitions, we must require the definiti

In C, how come a function may have several declarations but only one 开发者_开发问答definition? Can someone elaborate on that please!


In order to allow multiple definitions, we must require the definition be functionally identical - otherwise you must have some way to decide which to run, at which point you might as well give them different names.

Proving that two function definitions are identical is a non-trivial problem. Since functions may be declared in multiple translation units, you would need to compare them at the link stage in order to prove they were identical. This is a problem when you start dealing with compiler optimizations which may take into account the other contents of these translation units. For example, consider:

const char *foo() {
  return "world";
}

Simple enough, right? Now we compile two files. a.c contains only foo. b.c contains this as well:

const char *bar() {
  return "Hello world";
}

The compiler may choose to make foo()'s "world" point into the middle of bar()'s "Hello world". The linker must somehow determine that the two foo()s are identical, even though they point into non-identical constant data.

A bigger issue comes in when aliasing rules are considered. Consider:

void frob(int *p);

int foo() {
  int x = 1;
  x++;
  frob(&x);
}

Compiled alone, this might result in assembly code similar to:

foo:
    sub %esp, 4               ; allocate stack space for x
    mov dword [%esp], 2       ; set x to 2 (x++ combined with initialization)
    push %esp                 ; push %x to the stack as frob's argument
    call frob
    mov %eax, dword [%esp+4]  ; load the value of x into eax for the return value
    add %esp, 8               ; clear the stack of frob's argument and x
    ret                       ; return

Now let's compile it with a definition of frob in scope:

void frob(int *p) { /* no-op */ }

Now we have:

frob:
    ret                       ; return

foo:
    mov %eax, 2               ; return value = 2
    ret                       ; return

How can the linker tell the two foo definitions are identical?

Given the difficulties of proving function bodies identical, C opts to simply forbid you from defining the same function twice. C++ uses a different approach for inline and template functions; it simply doesn't check, and assumes they're identical.

As for declarations on the other hand, there are defined rules for proving compatibility, so there's no problem in allowing multiple compatible declarations.


The short answer is "historical reasons".

A declaration tells the compiler how to generate code to call the function.

A definition results in code to implement the function. Typically, the compiler generates assembly code that gets fed to an assembler, which generates object files that get fed to a linker. The compiler, assembler, and linker were traditionally written by different people... They were not really part of a single "package".

With multiple definitions, the compiler will emit multiple copies of the function. Then the linker will see the function defined multiple times and not know which one you are trying to call. The linker would typically then generate an error like "multiply-defined symbol xxx". The people who defined C did not want to put any extra burden on the linker implementors (like checking to see if the multiple definitions were identical), so they simply forbade this in the language.

With multiple declarations, the only burden is on the C compiler.

At least, this is my suspicion for the rationale.


It can have several declarations, but the all must be identical, but it doesn't make sense to have more than one definition. How would the compiler decide which one it should use?


Declarations are mostly used in header files so that other programs can interface with your program after compilation, but AFAIK you should stick to one declaration and one definition. Declaring it multiple times seems like an easy way to make your program needlessly complicated, since you'd have to ensure that all declarations are identical.

0

精彩评论

暂无评论...
验证码 换一张
取 消