Dig into the differences between declarations and definitions in C++

  • 2020-04-02 02:44:17
  • OfStack

              First, let's talk about the difference between declaration and definition.
              Declaration is to introduce a name into a program. A definition provides a unique description of an entity in a program. Declarations and definitions sometimes exist side by side.


    Such as int a;

   extern int b=1;

      An initializer is only declared if it does not exist in extern. Other cases are both definitions and declarations.

        However, a declaration is only a declaration in the following cases:


    1 : only function prototypes are provided. Such as void func(int,int);

    2: extern int a;

    3 : class A ; 

    4 : typedef The statement 

    5 : declaration of static data members defined in a class 

    Such as:


class A 
{ 
  public: 
  static int a;//The statement.
};

    In the following cases, a definition is just a definition:


   1 : defines and initializes a static data member outside of the class definition. Such as  A::a=0;

   2: Define non-inline member functions outside the class. 
        Declarations simply introduce a symbol into a scope. A definition provides a unique description of an entity in a program. It is ok to declare a symbol repeatedly in a given domain, but you cannot repeat the definition, otherwise a compilation error will result. The exceptions are member functions and static data members in a class, which are declared within the class but cannot have more than one.

Such as:

              To understand the difference between declaration and definition, you also need to understand internal and external links. Only when you understand them will you know the question at the beginning.

            At compile time, the compiler detects only program syntax and whether functions and variables are declared. If the function is not declared, the compiler gives a warning, but the target file can be generated. When linking programs, the linker looks for the implementation of the function in all the target files. If you can't find it, you'll get a Linker Error. Under VC, this error is usually a Link 2001 error, which means that the linker failed to find an implementation of the function.

          Links link symbols produced by different compilation units. There are two ways to link: internal and external.

          If a symbol name is local to its compilation unit and cannot be linked with the same name in another compilation unit, that symbol is an internal link. Internal linking means that access to this symbol is limited to the current compilation unit and is not visible to other compilation units.

            The static keyword represents a static global variable when applied to a global variable. But the scope is only within the scope of the current file. Even the extern declaration is not available in other files. Const is similar.

            A connection with a static, const keyword, and an enumeration type is internal.

            A symbol with an internal link cannot be applied outside the current file. To affect the rest of the program, place it in an. H file. At this point all the source files that contain this.h file have their own definition and are independent of each other.

            The definition of a class has an internal link that, because it is a definition, cannot be repeated in the same compilation unit. If it is needed in other compilation units, the class must be defined in the header file and included in other files. Use class a only in other files; Declarations are not possible because the class definition is an internal link and does not export symbols in the target file. Their undefined symbols are not parsed by other units. It's important to understand this.

        Inline functions also have internal links.

          In a multi-file program, if a symbol can interact with other compilation units when linked, the name has an external link. External links mean that the definition is not limited to a single compilation unit. It can generate external symbols in.o files. Can be accessed by other compilation units to resolve their undefined symbols. They must therefore be unique throughout the program, or they will result in duplicate definitions.

            Non-inline member functions, non-inline functions, and non-static free functions all have external links.

            All inlined functions have internal links, because the compiler replaces all calls to functions with the body of the function when possible, without writing any symbols to the.o file.

            A good way to determine whether a symbol is an internal or external link is to see if the symbol is written to the.o file.

            The first is the impact of the definition on the way you link, and the second is the impact of the declaration on the way you link.

            Because the declaration is only useful for the current compilation unit, the declaration does not write anything to the.o file.

            Such as extern int a;

            Int func ();

            These statements by themselves do not affect the contents of the.o file. Each one simply names an external symbol so that the current compilation unit can access the corresponding global definition if needed.

        The function call causes an undefined symbol to be written to the.o file. If a is not used in the file, it is not written to the.o file. The func function has a call to this function. This symbol is written to the target file. The.o file is then concatenated with the.o file that defines the symbol, and the previously undefined symbol is parsed.

        The above declaration may cause the symbol to be written to the target file. However, the following declaration does not cause the symbol to be written to the target file.

Such as:


typedef int Int ; 
Class A; 
struct s; 
union point; 


        Their links are also internal.

        Class declarations and class definitions are internal links. Only for the current compilation unit.

        The definition of a static class data member has external links. Such as


class A 
{ 
  static int a;//The statement. Has internal links.
} ; 

          The static data member a is just a declaration, but its definition a ::a=0; But with external links.

        C++ handles classes and enumerated types differently. For example, you can declare a class without defining it. However, you cannot declare an enumerated type without a definition.

        Based on the above analysis, we know that placing definitions with external links in header files is almost always a programming error. Because if the header file is contained by more than one source file, multiple definitions will exist and errors will occur when linking.

        The definition of placing an internal link in a header file is legal, but not recommended. Because header files are included in multiple source files, not only do they pollute the global namespace, but they also have their own entities in each compilation unit. It consumes a lot of memory space and can also affect machine performance.

        Const and static global variables are only valid within the scope of the current file. They have internal link properties.

      Here are some definitions that should or should not be written to header files:


//test.h 
#ifndef TEST_H 
#define TEST_H 
  int a;   //A has an external link and cannot be defined in the header file.
  extern int b=10 ; //Same as above.
  const int c=2;//C has internal links that can be set in header files but should be avoided.
  static int d=3;//Same as above.
  static void func(){} //Same as above.
  void func2(){} //With a.
  void func3();//You can. Just a statement. Does not cause the symbol name to be written to the target file.
class A 
{ 
  public: 
   static int e;//Yes, with internal links.
   int f ; // You can, Same as above.
   void func4();// Declare internal links. Same as above.
}; 
  A::e=10;//You cannot include a definition with an external link in a header file. The symbol name is not written to the target file.
  void A:func4()//No, class member functions. External connection.
{ 
 //,...... 
} 
#endif
 

          I'm sure you now understand why it's legal to declare a member function in a type and not implement it. You can also answer why the class definition is in the.h file. The implementation of the class can be placed in a CPP file with the same name. The teacher's previous introduction was that the compiler would automatically look for CPP files with the same name. In fact, because the CPP file stores the implementation of the member function, and the member function has the external link feature, it will generate symbols in the target file. This symbol is defined in this file. Other target files that call this member function also produce an undetermined symbol. The symbol is resolved after the two object files are joined. Notice that the static data member should be in the CPP file. You can't put it in an.h file.

          Definitions with internal links can be defined in the CPP file without affecting the global symbol space. But in the CPP file scope, avoid defining (and not forbidding) data and functions that are not declared static because they have external links.

Such as


 int a; 
void func() 
{  
    ...... 
} 

          Having external links in the above definition may potentially conflict with other symbolic names in the global namespace. If you do need to use global variables or functions. You can add the static keyword to them. Limit its scope to the current file and having internal links will not affect the global namespace. Because inline and static free functions, enumerations, and const-type data all have internal links, they can be defined in a CPP file without affecting the global namespace.

          Typedefs and macro definitions do not introduce symbols into.o files, and they can also appear in CPP files without affecting the global namespace.

          A typedef creates an alias for an existing type. Instead of creating a new type. It does not provide type safety. Such as


typedef int IntA ;  
typedef int InB ;   
 

            Using IntB where IntA is needed is error free. They can be substituted for each other. Because of this we say it does not provide type safety. But typedefs are often used when defining a function type to make the definition clearer.

          The standard c library provides an assert macro to ensure that a given expression value is non-zero. Otherwise, an error message is printed and execution is terminated. Assert works only if NDEBUG is not defined in the program. Once NDEBUG is defined   , an assert statement will be ignored. Note the difference between ASSERT and VC. ASSERT is provided by vc. _DEBUG only works when it is defined.

_DEBUG is defined in vc's DEBUG mode. NDEBUG is defined in RELEASE mode.

      Well, I'm sure you understand the question at the beginning. If you don't understand, please leave a message. If there is a mistake, also please not hesitate to correct!!

      The above contents refer to Large Scale C++ software design.


Related articles: