Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confusion between declaration and definition of a variable in C

Tags:

c

variables

I am new to C and I experience some confusion between the declaration and definition of a variable. Another thing I would like to know is if the following is true:

"Declaration appears many times and definition comes once."

Also:

int x; 

Is this a declaration only? Since memory is allocated for x then why isn't this a definition instead of a declaration?

like image 405
Amit Singh Tomar Avatar asked Dec 06 '22 23:12

Amit Singh Tomar


2 Answers

Simply writing int x; at either global scope or local scope, is both a declaration and definition. Typically, the declaration tells the compiler "This variable will exist, at some point, under this name, so you can use it." The definition tells the compiler to actually arrange for the variable to be created - obviously this can only happen once.

Typically the way you'll use this is by putting in a header file:

// Foo.h
#ifndef FOO_H
#define FOO_H // make sure structs aren't redefined

extern int bar; // Declare a variable bar

#endif

And in a single source file

#include "foo.h"
int bar; // Define bar

If you were to define bar in multiple files, you would get an error; you can't create the variable twice. But you do have to tell the compiler about it in every source file you use bar in. Hence the extern declaration.

The precise semantics are defined in §6.9.2 of the C standard and can be summarized as follows:

  • When a variable is declared at file scope with an initializer, it is an external definition. (§6.9.2/1)
  • When a variable is declared at file scope without an initializer, and without a storage-class specifier or with the static storage-class specifier, it is a tentative definition. If the translation unit (file) has one or more tentative definitions and no external definition, the compiler automatically adds a true file scope declaration at the end of the translation unit, with a zero initializer. (§6.9.2/2)

What this means is that, strictly speaking, int x; is not a definition; but it automatically creates a definition if and only if there is no other definition with an initializer, and no static definition (this third case is undefined behavior due to linkage disagreement per §6.2.2/7)

Note that extern int x; is not an external definition. It is a declaration with an extern storage class specifier. As such, extern int x; alone does not cause a definition to be created, but if you have both:

extern int x;
int x;

Then you will end up having a definition created at some point in the file.

It is also, technically speaking, legal to do this:

extern int x;
int x;
int x = 42;

In this case, the int x; in the middle is superfluous and has no effect. That said, this is poor form, as it's confusing in this case where the actual definition is.

like image 158
bdonlan Avatar answered Apr 05 '23 23:04

bdonlan


This isn't something you see too much in C, but it works like this:

In a header file, you can have a line like this:

extern int x; //declaration

Because of the extern modifier, this tells the compiler that there is an int named x somewhere. The compiler doesn't allocate space for it - it just adds int x to the list of variables you can use. It'll only allocate space for x when it sees a line like this:

int x; //definition

You can see that because only the int x; line changes your executable, you can have as many extern int x; lines as you feel like. As long as there's only int x; line, everything will work like you want it to - having multiple declarations doesn't change a thing.

A better example comes from C++ (sorry if this is a C-only question - this applies to structs as well, but I don't know the syntax off the top of my head):

class Pineapple; //declaration

Pineapple* ptr;  //this works
Pineapple pine;  //this DOES NOT work

This declaration tells the compiler that there's a class called "Pineapple". It doesn't tell us anything about the class (how big it is, what its members are). We can use pointers to Pineapples now, but we can't yet have instances - we don't know what makes up a Pineapple, so we don't know how much space an instance takes up.

class Pineapple
{
public:
    int ounces;
    char* name;
}; //definition

Pineapple* ptr;   //still works
Pineapple pine;   //this works now too!
//we can even get at member variables, 'cause we know what they are now:
pine.ounces = 17;

After a definition, we know everything about the class, so we can have instances, too. And like the C example, you can have multiple declarations, but only one definition.

Hope this helps!

like image 31
Xavier Holt Avatar answered Apr 06 '23 01:04

Xavier Holt