Author Topic: can't figure out difference between declaration and definition  (Read 4185 times)

0 Members and 1 Guest are viewing this topic.

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: can't figure out difference between declaration and definition
« Reply #25 on: January 12, 2023, 04:00:05 pm »
An "extern void Function2(void);" would tell the compiler/linker that Function2() is in another file.
What makes you think that?
This time I'll refrain from quoting the standard.
Just consider this: when you include a file, its text is for all purposes inlined in the including file.
If what you say were true, the common practice of including xxx.h from xxx.c (as sokoloff suggests) would not work!

It is, indeed, common practice because it helps with catching errors such as having incompatible declarations and definitions of an object or function: as translation units are compiled separately, it's the only way the compiler can tell you that (e.g.) the function declaration in the .h has a different signature than the one in its definition in the .c.
In general, linkers will happily ignore the problem, unless link time optimization is used.
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Online Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6253
  • Country: fi
    • My home page and email address
Re: can't figure out difference between declaration and definition
« Reply #26 on: January 12, 2023, 04:36:02 pm »
Consider this thought experiment, to clarify the difference between declaration and definition:

You have a data structure, a network or graph, consisting of two different types of nodes.
Each node type can refer to four nodes of the same type, and two nodes of the different type.
How do you define the structures?  When you define the first one, the other one is still undefined, so how do you refer to that?



We do that by declaring the structures before we define them:
Code: [Select]
struct one;
struct two;

struct one {
    struct one *ones[4];
    struct two *twos[2];
    // Contents of the node omitted
};

struct two {
    struct two *twos[4];
    struct one *ones[2];
    // Contents of the node omitted
};

We can do the same by defining the two node types first (node_one and node_two, becoming new variable types) based on as yet undefined structure types, which also declares the structure types:
Code: [Select]
typedef  node_one  struct one;
typedef  node_two  struct two;

struct one {
    node_one *ones[4];
    node_two *twos[2];
    // Contents of the node omitted
};

struct two {
    node_two *twos[4];
    node_one *ones[2];
    // Contents of the node omitted
};

Similarly, we can declare a function before we define it, so that two functions can call each other.



The C standard defines declaration and definition in for example C11 6.5p5 as
Quote
A declaration specifies the interpretation and attributes of a set of identifiers.
A definition of an identifier is a declaration for that identifier that:
— for an object, causes storage to be reserved for that object;
— for a function, includes the function body;
— for an enumeration constant, is the (only) declaration of the identifier;
— for a typedef name, is the first (or only) declaration of the identifier.
 

Offline madires

  • Super Contributor
  • ***
  • Posts: 7763
  • Country: de
  • A qualified hobbyist ;)
Re: can't figure out difference between declaration and definition
« Reply #27 on: January 12, 2023, 05:20:56 pm »
An "extern void Function2(void);" would tell the compiler/linker that Function2() is in another file.
What makes you think that?
This time I'll refrain from quoting the standard.
Just consider this: when you include a file, its text is for all purposes inlined in the including file.
If what you say were true, the common practice of including xxx.h from xxx.c (as sokoloff suggests) would not work!

Yes, and no. ;D Most C variants/versions/compilers take any function declaration with an implicit 'extern' (this was mentioned before). To override this you'd have to add a 'static' to make a function local only. However, some people think that this auto-extern is a flaw as it contradicts the explicit use of 'extern' for variables. So there are also C compilers following that idea. For better portability and readability I prefer to add an explicit 'extern' to function declarations for functions outside of the local file.
 

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: can't figure out difference between declaration and definition
« Reply #28 on: January 12, 2023, 05:47:04 pm »
Well, no standard compliant compiler should do that.
Then if if we are talking about a language that is almost, but not quite, entirely unlike C all bets are off.

BTW, I also use extern for function declarations in .h files, but this is just my personal taste for consistency.
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Online mfro

  • Regular Contributor
  • *
  • Posts: 210
  • Country: de
Re: can't figure out difference between declaration and definition
« Reply #29 on: January 12, 2023, 06:01:24 pm »
... So there are also C compilers following that idea...

I would suppose these compilers (never came across such) must be pretty old as such behaviour would be violating the standard.

Regarding the (apparently) superflous use of the extern keyword with function declarations: there is one situation (yet another inconsistency in the C standard) where it matters: extern does matter in conjunction with inline.
An inline function by default does *not* have extern linkage, i.e. it can't be called from outside the current translation unit. If there is an additional function declaration visible that mentions extern (or is missing inline), an additional incarnation of the function is generated that *can* be called from other translation units (note that gcc does not strictly adhere to the standard here).
« Last Edit: January 12, 2023, 06:04:43 pm by mfro »
Beethoven wrote his first symphony in C.
 

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 151
  • Country: us
Re: can't figure out difference between declaration and definition
« Reply #30 on: January 12, 2023, 06:35:06 pm »
We do that by declaring the structures before we define them:
Code: [Select]
struct one;
struct two;

struct one {
    struct one *ones[4];
    struct two *twos[2];
    // Contents of the node omitted
};

struct two {
    struct two *twos[4];
    struct one *ones[2];
    // Contents of the node omitted
};

We can do the same by defining the two node types first (node_one and node_two, becoming new variable types) based on as yet undefined structure types, which also declares the structure types:
Code: [Select]
typedef  node_one  struct one;
typedef  node_two  struct two;

struct one {
    node_one *ones[4];
    node_two *twos[2];
    // Contents of the node omitted
};

struct two {
    node_two *twos[4];
    node_one *ones[2];
    // Contents of the node omitted
};

Well, for the sake of completeness, in cases like that one doesn't have to pre-declare struct types in C. When you refer to a yet-unknown struct type in C, the language always treats it as a declaration of a new type. So, in the first version of the code you don't need to make those initial `struct` declarations at all. The following is valid and will work as intended as well (i.e. it is equivalent to your version):

Code: [Select]
/* Types `struct one` and `struct two` are unknown at this point */

struct one {
    struct one *ones[4];
    struct two *twos[2];
    /* This is fine. In addition to declaring a field it also
       introduces an incomplete file-scoped type `struct two` */
};

/* The following is a complete declaration of the same `struct two`
   introduced above */
struct two {
    struct two *twos[4];
    struct one *ones[2];
};

When introducing new types on-the-fly one has to pay attention to scoping rules, but in this example everything is fine. I personally consider it a good practice to pre-declare types (and follow the style from your second example), but still...
« Last Edit: January 13, 2023, 05:00:51 pm by TheCalligrapher »
 
The following users thanked this post: newbrain

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 151
  • Country: us
Re: can't figure out difference between declaration and definition
« Reply #31 on: January 12, 2023, 06:55:04 pm »
However, some people think that this auto-extern is a flaw as it contradicts the explicit use of 'extern' for variables. So there are also C compilers following that idea.

That's a rather strange way to perceive it.

Everywhere in C external linkage is a default for file-scope variables and functions. There's never a need to use `extern` keyword, aside from a strange niche case with turning a variable definition into a non-defining declaration when declaring global variables. Moreover, most C compilers support a popular historical non-standard extension, when it is OK to provide multiple definitions of a global variable without an initializer scattered across different translation units. This extension basically makes explicit `extern` completely unnecessary.

And, on the contrary, some people consider this a flaw: that this latter detail is non-standard and that we still have to sometimes use `extern` with variables. And even though it is a non-standard extension, it does emphasize the fact that the language is tailored towards avoiding explicit `extern`.  And that is what most people normally do: avoid using `extern` entirely.

(Note: since C99 explicit `extern` has another niche usage: with `inline` functions. But that is a fairly different topic.)

For better portability and readability I prefer to add an explicit 'extern' to function declarations for functions outside of the local file.

It has zero effect on portability. And it has a pronouncedly negative impact on readability, by introducing a lot of unnecessary clutter.

I do see habitual use of redundant `extern` on function declarations in some code from time to time. But most of the time it just an ugly cargo-cult followed by incompetent people: some people simply don't know that it is unnecessary. It it very similar to other popular cargo-cults, like casting results of memory allocation functions.
« Last Edit: January 12, 2023, 06:58:35 pm by TheCalligrapher »
 
The following users thanked this post: SiliconWizard

Online Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6253
  • Country: fi
    • My home page and email address
Re: can't figure out difference between declaration and definition
« Reply #32 on: January 12, 2023, 07:05:39 pm »
Well, for the sake of completeness, in cases like that one doesn't have to pre-declare struct types in C.
Sshhhh, quiet! ;D

The only other example I could come up with was one using two functions to experiment with the Collatz conjecture, but it was nowhere as simple.  (And the single recursive function one is also much cleaner.)

Because you broke my believability, I now demand you to come up with a good example of the difference between declarations and definitions!  8)

When intoducing new types on-the-fly one have to pay attention to scoping rules, but in this example everything is fine. I personally consider it a good practice to pre-declare types (and follow the style from your second example), but still...
Yeah, and it's not like any compilers I've used in the past required the declarations beforehand..  It's only for us humans that I do things like that.
 

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: can't figure out difference between declaration and definition
« Reply #33 on: January 12, 2023, 07:15:15 pm »
Moreover, most C compilers support a popular historical non-standard extension, when it is OK to provide multiple definitions of a global variable without an initializer scattered across different translation units.
[...]
I do see habitual use of redundant `extern` on function declarations in some code from time to time. But most of the time it just an ugly cargo-cult followed by incompetent people: some people simply don't know that it is unnecessary. It it very similar to other popular cargo-cults, like casting results of memory allocation functions.
I'm glad gcc has finally stopped doing that since version 10 (still available using an option, for old - wrong - code).
This makes using extern in with variable declarations mandatory in case one's accessing them from another translation unit.

On the second point: yes, I know perfectly well that it's not needed for functions.
But, given the above, I prefer consistency - the visual clutter does not annoy me (in this case) - call it a (bad) habit, but now I'll climb back in my bamboo control tower.
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8172
  • Country: fi
Re: can't figure out difference between declaration and definition
« Reply #34 on: January 12, 2023, 07:26:56 pm »
Completely equivalent, regardless of which file and scope they are in:
Code: [Select]
extern void func(int arg);
void func(int arg);

Contrary to that, these are not equivalent:
Code: [Select]
extern int val;
int val;

Former is 100% surely only a declaration. Latter is usually also a definition, but as explained by TheCalligrapher above, most compilers allow globals to be "defined" multiple times, combining them into just one definition. I don't like it, so I use this pattern:

module1.h
Code: [Select]
extern int module1_public_thing;

module1.c
Code: [Select]
int module1_public_thing;

module2.c
Code: [Select]
#include "module1.h"
void something()
{
      int thing = module1_public_thing + 42; // access it here
}

But only rarely you directly share globals like this. errno would be one typical example.
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14464
  • Country: fr
Re: can't figure out difference between declaration and definition
« Reply #35 on: January 12, 2023, 07:35:33 pm »
For sure, a function prototype just declares the prototype. It doesn't require any kind of 'extern' qualifier, and adding one usually shows a poor understanding of the C language.

As to global variables, multiple definitions are horrible, and recent versions of GCC (and I guess Clang has followed) make them deprecated by default (you need to set a specific compiler option to enable them.) So only one definition (ideally in the source file where it makes most sense) and then 'extern' declarations to access them elsewhere is the way to go IMHO.


 

Offline sokoloff

  • Super Contributor
  • ***
  • Posts: 1799
  • Country: us
Re: can't figure out difference between declaration and definition
« Reply #36 on: January 12, 2023, 07:36:22 pm »
The C language standard calls this second one a "tentative definition" (C99 6.9.2/2)

Quote from: The C Language Standard
A declaration of an identifier for an object that has file scope without an initializer, and
without a storage-class specifier or with the storage-class specifier static, constitutes a
tentative definition. If a translation unit contains one or more tentative definitions for an
identifier, and the translation unit contains no external definition for that identifier, then
the behavior is exactly as if the translation unit contains a file scope declaration of that
identifier, with the composite type as of the end of the translation unit, with an initializer
equal to 0.
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8172
  • Country: fi
Re: can't figure out difference between declaration and definition
« Reply #37 on: January 12, 2023, 07:41:29 pm »
For sure, a function prototype just declares the prototype. It doesn't require any kind of 'extern' qualifier, and adding one usually shows a poor understanding of the C language.

Not necessarily - one can use the keyword to communicate the intent to a human reader. Then it's more a question about taste than understanding of the language.

I use it from time to time. When function prototype is in a header, or in the global file scope of a .c file, obviously there will be no extern keyword added. But then, if I need to call one odd function from somewhere as a quick hack, and don't feel like adding the declaration into a relevant .h file, I might just declare the function right before calling it, at the function scope / block scope. In such case, adding extern underlines the fact this weird looking thing in the middle of code is a declaration:

Code: [Select]
void func()
{
    if(asdf == 0x42)
    {
        extern void self_destroy();
        self_destroy();
    }
}

Not suggesting anyone to do this, but it communicates to the human reader: this exists somewhere and I forgot where; call it right now anyway. It also communicates this won't be used anywhere else, because then I would have added it to a header properly :).
« Last Edit: January 12, 2023, 07:43:46 pm by Siwastaja »
 
The following users thanked this post: newbrain, DiTBho

Offline sokoloff

  • Super Contributor
  • ***
  • Posts: 1799
  • Country: us
Re: can't figure out difference between declaration and definition
« Reply #38 on: January 12, 2023, 09:30:30 pm »
As to global variables, multiple definitions are horrible, and recent versions of GCC (and I guess Clang has followed) make them deprecated by default (you need to set a specific compiler option to enable them.) So only one definition (ideally in the source file where it makes most sense) and then 'extern' declarations to access them elsewhere is the way to go IMHO.
This was another TIL.

It came in gcc 10: https://gcc.gnu.org/gcc-10/porting_to.html#common
 

Offline IDEngineer

  • Super Contributor
  • ***
  • Posts: 1926
  • Country: us
Re: can't figure out difference between declaration and definition
« Reply #39 on: January 12, 2023, 09:31:49 pm »
I don't like it, so I use this pattern....
I do exactly this same thing. Eliminates confusion and doesn't rely on one-off compiler quirks.
 

Offline madires

  • Super Contributor
  • ***
  • Posts: 7763
  • Country: de
  • A qualified hobbyist ;)
Re: can't figure out difference between declaration and definition
« Reply #40 on: January 12, 2023, 09:45:26 pm »
For better portability and readability I prefer to add an explicit 'extern' to function declarations for functions outside of the local file.

It has zero effect on portability. And it has a pronouncedly negative impact on readability, by introducing a lot of unnecessary clutter.

I do see habitual use of redundant `extern` on function declarations in some code from time to time. But most of the time it just an ugly cargo-cult followed by incompetent people: some people simply don't know that it is unnecessary. It it very similar to other popular cargo-cults, like casting results of memory allocation functions.

I love to add lots of clutter, like comments explaining things. Makes long term maintenance much easier. The argument that clutter implies incompetence is a preconception and simply nonsense. In many cases it's done intentionally to convey a hint or message, either for myself or for someone else to help writing or maintaining the code. Not long ago this practice was considered a good coding style and was tought to students.

BTW, when I'm dealing with clutter-free code I often see poor algorithms and other strange things, just my personal funny experience.

For sure, a function prototype just declares the prototype. It doesn't require any kind of 'extern' qualifier, and adding one usually shows a poor understanding of the C language.

Same preconception as above. :( Just because you prefer a clutter-free coding style doesn't mean that any other style is a sign of incompetence.
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8172
  • Country: fi
Re: can't figure out difference between declaration and definition
« Reply #41 on: January 13, 2023, 10:46:05 am »
Indeed, one could always use extern keyword for all declarations (not making difference between variables and functions); that would be highly logical. I don't agree following a logical style rule is incompetence. Of course, random sprinkling of extern here and there suggests either incompetence or some kind of attention problem.

The only problem is the poor name choice for the keyword, but same can be said with many other keywords; static is even worse. We just need to live with these and learn the true meanings, and assume others working with C also learn them.

And I don't suggest anybody do this:

#define declare extern
#define private static
#define public

Think how nice it would be if we had a microcontroller-oriented language with no reserved words so anyone could come up with their own keywords in their own language!  :D
« Last Edit: January 13, 2023, 10:50:08 am by Siwastaja »
 

Offline AndyBeez

  • Frequent Contributor
  • **
  • Posts: 856
  • Country: nu
Re: can't figure out difference between declaration and definition
« Reply #42 on: January 13, 2023, 12:22:50 pm »
To the OP, the use of the terms declare or define get somewhat muddy, especially in other languages and with other programmers from different non C backgrounds.

I would for argument say that we declare a named space in memory that is used either a variable or a constant, and then define it's type. After-which we use arguments to initialise the value - or values - for the type. Of course, that declared value has scope within the code. When the value goes out of scope, the space in memory is destroyed; a state which some programmers refer to as the value becoming undeclared. ???
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8172
  • Country: fi
Re: can't figure out difference between declaration and definition
« Reply #43 on: January 13, 2023, 01:09:48 pm »
I would for argument say that we declare a named space in memory that is used either a variable or a constant, and then define it's type. After-which we use arguments to initialise the value - or values - for the type.

Please don't confuse the OP with such BS. Basically everything was wrong with this.
 

Offline sokoloff

  • Super Contributor
  • ***
  • Posts: 1799
  • Country: us
Re: can't figure out difference between declaration and definition
« Reply #44 on: January 13, 2023, 01:14:10 pm »
The only problem is the poor name choice for the keyword, but same can be said with many other keywords; static is even worse. We just need to live with these and learn the true meanings, and assume others working with C also learn them.
Agreed. There are a few things in any professional field where "that's how it's been for 50+ years and you're not going to be the one we change it for, so you better just learn it." (That's not to say anything bad about OP or the thousands of other devs who initially struggle with this, but realistically, it's something that takes an hour or so to learn and then is entirely second nature by the second month you're working on any codebase larger than a solution to an academic problem set.

And I don't suggest anybody do this:

Code: [Select]
#define declare extern
#define private static
#define public
Certainly not if you're going to go on to learn c++ or switch back and forth between them!
 

Offline DiTBho

  • Super Contributor
  • ***
  • Posts: 3915
  • Country: gb
Re: can't figure out difference between declaration and definition
« Reply #45 on: January 13, 2023, 01:24:30 pm »
I'm glad gcc has finally stopped doing that since version 10 (still available using an option, for old - wrong - code)

yup, otherwise you cannot re-compile gcc-v2.95(1) (the last one that *actually* works for 88k) with host_gcc >= { v10, v11, v12, ... }

Yesterday I had two minutes of full solid panic on my HPPA, before reading the manual and finding that "holy retro-option".


(1) the same apply for all the old part of Haiku still based (don't ask my why?) on gcc-v2.95, hence even modern gcc-v10 toolchains are multi-library-multi-cc1/cc1pp (c,c++) hybrid.

Life is ... not easy  :-//
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline AndyBeez

  • Frequent Contributor
  • **
  • Posts: 856
  • Country: nu
Re: can't figure out difference between declaration and definition
« Reply #46 on: January 13, 2023, 01:26:22 pm »
I would for argument say that we declare a named space in memory that is used either a variable or a constant, and then define it's type. After-which we use arguments to initialise the value - or values - for the type.

Please don't confuse the OP with such BS. Basically everything was wrong with this.
Explain? Or are you such an expert that you have never have to?
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8172
  • Country: fi
Re: can't figure out difference between declaration and definition
« Reply #47 on: January 13, 2023, 01:29:37 pm »
I would for argument say that we declare a named space in memory that is used either a variable or a constant, and then define it's type. After-which we use arguments to initialise the value - or values - for the type.

Please don't confuse the OP with such BS. Basically everything was wrong with this.
Explain? Or are you such an expert that you have never have to?

It's already all in this thread. Declaration does not reserve space in memory, definition does, that went the wrong way. Declaration does give the type, that's the whole point. Definition does not define any more type than declaration already does. And initializer is not argument.

If you swap definition and declaration, you are closer, but still not there.

When every point made is completely wrong, it is easier just to state this fact instead of enumerating every point separately, but here you are anyway.
 

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 151
  • Country: us
Re: can't figure out difference between declaration and definition
« Reply #48 on: January 13, 2023, 05:17:02 pm »
Because you broke my believability, I now demand you to come up with a good example of the difference between declarations and definitions!  8)

"Declarations and definitions" of what specifically? Your original example looks like an attempt to illustrate the difference between "declarations and definitions" for struct types in C. However, terminologically this is not applicable to C at all. C language does not support the concept of "definition" for struct types. So, I can't really come up with an example for struct types. Pedantically speaking, it is impossible,

In C the term "definition" is only encountered in conjunction with: object definitions (i.e. definitions of variables), function definitions, type definitions (refers to `typedef` specifically) and macro definitions.

A declaration of a struct type is always a declaration, never a definition:

Code: [Select]
struct A;
/* A declaration of incomplete type `struct A`.
   Sometimes informally referred to as "forward declaration" */

struct B /* A declaration of complete type `struct B` */
{
  int x, y;
};

It was C++ that decided to change things drastically, and separated such class declarations into "declarations" and "definitions". In C++ the first declaration above is a "declaration" ("just a declaration"), while the second one is a "definition". But this is C++ specific.
« Last Edit: January 13, 2023, 06:20:49 pm by TheCalligrapher »
 

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 151
  • Country: us
Re: can't figure out difference between declaration and definition
« Reply #49 on: January 13, 2023, 05:37:49 pm »
The C language standard calls this second one a "tentative definition" (C99 6.9.2/2)

Tentative definitions is a perfectly standard feature of C language, which "works" within one translation unit. It is a feature that permits you to specify multiple definitions of the same variable within the same translation unit

Code: [Select]
/* File scope */
int a;
int a;
int a, a, a, a, a;

The above is OK in C because these are tentative definitions. There's nothing non-standard about the above.

However, this feature is, again, completely isolated within each translation unit. It has no "external" effects. It has nothing to do with the fact that some compilers permit you to define the same variable in multiple translation units. This permission has nothing to do with tentative definitions. This permission is a non-standard extension. It is popular mistake to just explain this behavior as an example of "tentative definitions".

(One can probably suggest that this extension is a "natural side effect" of tentative definitions... But in reality it is really not as "natural" as it might seem at the first sight.)
« Last Edit: January 14, 2023, 03:58:04 am by TheCalligrapher »
 
The following users thanked this post: Siwastaja, SiliconWizard, DiTBho


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf