1
void test(void){
  //
}
void test(void); // <-- legal

int main(){
 test();

 int i = 5;
 // int i;          <-- not legal
 
 return 0;
}

I understand that functions can have multiple declarations but only 1 definition, but in my example the declaration is coming after the definition. Why would this be useful? Same cannot be done with block scoped variables.

I found this post which explains the behaviour in C++, not sure if the same applies to C:

Is a class declaration allowed after a class definition?

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
Dan
  • 2,694
  • 1
  • 6
  • 19
  • 2
    The block-scoped variable is actually *defined* twice in this example. It’s impossible to declare a non-`extern` block-scoped variable without defining it. – user3840170 Jul 24 '21 at 15:46
  • 3
    Your function is defined once and declared twice. This is allowed. Your second "`int i`" is a second definition, thus is not allowed. –  Jul 24 '21 at 15:47
  • 3
    *"Same cannot be done with block scoped variables"* because those are *also* definitions. – StoryTeller - Unslander Monica Jul 24 '21 at 15:47
  • "Your function is defined once and declared twice" , I guess due to the `Every definition is a declaration` rule right? but still the declaration is coming after the definition is fine? – Dan Jul 24 '21 at 15:49
  • So are you asking whether the redeclaration of functions is legal, or when it could be useful, or how to do the same with variables? – GSerg Jul 24 '21 at 15:50
  • 1
    There are no classes in C so your link does not apply. – Rob Jul 24 '21 at 15:50
  • @GSerg i'm asking why function declaration coming after its own full definition is allowed? this seems pretty useless. a declaration BEFORE the definition is used all the time yes. – Dan Jul 24 '21 at 15:53
  • 1
    Frame challange: what benefit is there to disallowing it? What would be *gained* by making compilers halt on this? Any answer that is about a personal sense of aesthetics is not acceptable though. – StoryTeller - Unslander Monica Jul 24 '21 at 15:56
  • @Dan Why would it not be allowed? Why would you want to write extra compiler code to not forbid something that is unambiguous? – DarkAtom Jul 24 '21 at 15:57
  • So I guess since its harmless and pointless the compiler just lets it go? @YvesDaoust I also want to confirm the above statement "Your function is defined once and declared twice." is this related to the `Every definition is a declaration` rule? – Dan Jul 24 '21 at 15:58
  • 1
    Yes. Every *definition* is a declaration. A *declaration* simply tells the compiler that you promise this thing is defined elsewhere. The *definition* is what causes space to be reserved for it. – David C. Rankin Jul 24 '21 at 16:03
  • Ooops, sorry, I counted the call as a declaration... –  Jul 24 '21 at 16:30
  • @YvesDaoust no but still you might be right, *Every definition is a declaration* so I have one definition which is also a declaration, and the original declaration. so 2 declaration and 1 definition. – Dan Jul 24 '21 at 16:32
  • I did not intend to count the definition as a declaration. –  Jul 24 '21 at 16:53

3 Answers3

4

The underlying reason has to do with the way programs are typically compiled and linked on systems on which C is the "natural language", and the origin of the C language. The following describes conceptually how a program is generated from a collection of source files with static linking.

A program (which may or may not be written in C) consists of separate units — the C term is "translation units", which are source files — which are compiled or assembled to object files.

As a very rough picture such object files expose data objects (global variables) and executable code snippets (functions), and they are able to use such entities defined in other translation units. For the CPU, both are simply addresses. These entities have names or labels called "symbols" (function names, variable names) which an object file declares as "needed" (defined elsewhere) or "exported" (provided for use elsewhere).

On the C source code level the names of objects that are used here but defined elsewhere are made known to the compiler by "extern" declarations; this is true for functions and variables alike. The compiler conceptually generates "placeholder addresses" whenever such an object is accessed. It "publishes" the needed symbols in the object file, and the linker later replaces the symbolic placeholders with the "real" addresses of objects and executable code snippets when it creates an executable.

It does not hurt to declare the use of an external object or function multiple times. No code is generated anyway. But the definition, where actual memory is reserved for an object or executable code, can in general only occur once in a program, because it would otherwise be a duplicate code or object and create an ambiguity. Local variables don't have declarations like global variables; there is no need to declare their use far away from their definition. Their declaration is always also a definition, as in your example, therefore can only occur once in a given scope. That is not different for global variable definitions (as opposed to extern declarations) which can only occur once in the global scope.

Peter - Reinstate Monica
  • 15,048
  • 4
  • 37
  • 62
3

Let's say you have these files:

// foo.h
#pragma once
void foo();
// helpers.h
#pragma once
#include "foo.h"

// ...

void bar();
// foo.c

void foo() {
   // ...
}

#include "helpers.h"

// ...

Here, there is a declaration of foo after it's fully defined. Should this not compile? I think it's totally reasonable to expect #include directives to not have such effects.

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
0

I understand that functions can have multiple declarations but only 1 definition, but in my example the declaration is coming after the definition.

So?

Why would this be useful?

At minimum, it is useful for simplifying the definition of the language. Given that functions may be declared multiple times in the same scope, what purpose would be served by requiring the definition, if any, to be the last one? If multiple declaration is to be allowed at all -- and there is good reason for this -- then it is easier all around to avoid unnecessary constraints on their placement.

Same cannot be done with block scoped variables.

That's true, but for a different reason than you may suppose: every block-scope variable declaration is a definition, so multiple declarations in the same scope result in multiple definitions in the same scope, in violation of the one-definition rule.

A better comparison would be with file-scope variable declarations, which can be duplicated, in any order relative to a single definition, if present.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157