码迷,mamicode.com
首页 > 其他好文 > 详细

Cpp Chapter 9: Memory Models and Namespaces Part2

时间:2018-10-05 21:33:39      阅读:155      评论:0      收藏:0      [点我收藏+]

标签:oid   names   repo   hat   als   better   with   one   port   

9.2.4 Static duration, external linkage

) External variables

External variables are defined outside, thus external to any function.It is also termed global variables, which could be accessed in any function that follow‘s the external variable‘s definition in the file.

) one definition rule(odr)

One definition rule: there can be only one definition of a variable.
C++ has two types of variable declarations:
definition declaration, or simply called definition, which allocates memory for the variable.
referencing declaration, or simply called declaration, which does not cause the allocation of memory because it refers to an existing variable.This type of declaration uses the keyword extern and does not provide initialization, otherwise it is not a declaration but a definition, causing the memory to be allocated:

double up; // definition, up set to 0
extern int down; // declaration, down should be defined elsewhere
extern int left = 2; // definition because initialized

If you are using external variable in separate files, remember that only one file could contain the definition, other declarations should go with the keyword extern:

// file01.cpp
extern int cats = 20; // definition
int dogs = 22; // definition
int fleas; // definition
// file02.cpp
extern int cats; // declaration, cats defines in file01
extern int dogs; // declaration, dogs defines in file01
//file98.cpp
extern int cats;
extern int dogs;
extern int fleas; // all declaration, using variables defined in file01

Noteworthy that extern in "extern int cats" in file01 isn‘t necessary, omitting it produces same effect.

) variable overlapping

When you declare a local variable inside a function with a same name of a using global variable, it actually hides the global variable.
C++ provides scope resolution operator :: to cope with this. In functions where global and local variables sharing the same name are used, ::variable accesses the global version.
Noteworthy that altering global variable causes its value to change in all files.
Here‘s an example:

// external.cpp -- external variables
// compile with support.cpp
#include <iostream>
using namespace std;
double warming = 0.3; // external variable definition
void update(double dt);
void local();

int main()
{
    cout << "Global warming is " << warming << " degrees.\n";
    update(0.1);
    cout << "Global warming is " << warming << " degrees.\n";
    local();
    cout << "Global warming is " << warming << " degrees.\n";
    return 0;
}
// support.cpp -- use external variable
// compile with external.cpp
#include <iostream>
extern double warming; // external variable declartaion here: defined in external.cpp
void update(double dt);
void local();

using std::cout;
void update(double dt)
{
    extern double warming; // optional redeclaration
    warming += dt; // use global
    cout << "Updating global warming to " << warming;
    cout << " degrees.\n";
}

void local()
{
    double warming = 0.8; // use local varaible
    cout << "Local warming = " << warming << " degrees.\n";
    cout << "But global warming = " << ::warming << " degrees.\n"; // using :: scope resolution operator to access global
}

In support.cpp, the update() changes global variable value. The warming and ::warming in local() uses local(0.8) and global(0.4) variables respectively.


9.2.5 Static duration, internal linkage

Applying the static modifier to a file-scope variable gives an internal linkage:

static int thing; // internal linkage

) variable overlapping:

Rules if you use internal and external variables with same names:

// file1
int errors = 20; // external definition
// file2
static int errors = 10; // internal definition, don‘t contradict with file1
static double thing = 6.5; // internal definition
cout << errors; // the answer should be 10
// file3
double thing = 6.7; // external definition, don‘t contradict with file2
cout << thing; // the answer should be 6.7

You can use static variable with internal linkage to share values between functions within the same file.
Here comes example:

// twofile1.cpp -- variables with external and internal linkage
// to be compiled with twofile2.cpp
#include <iostream>
int tom = 3; // external definition
int dick = 30; // external definition
static int harry = 300; // internal definition

void remote_access();

int main()
{
    using namespace std;
    cout << "main() reports the following addresses:\n";
    cout << &tom << " = &tom, " << &dick << " = &dick, " << &harry << " = &harry\n";
    remote_access();
    return 0;
}
// twofile2.cpp -- variables with internal and external linkage
#include <iostream>
extern int tom; // external declaration; tom defined in twofile1.cpp
static int dick = 10; // internal definition; overrides external dick in twofile1.cpp
int harry; // external definition; no conflict with twofile1.cpp‘s internal harry

void remote_access()
{
    using namespace std;
    cout << "remote_access() reports the following addresses:\n";
    cout << &tom << " = &tom, " << &dick << " = &dick, " << &harry << " = &harry\n";
}

The address of tom is same in both files because tom is external linkage and re-declared in file2, but dick and harry have different addresses in both files, due to the fact that dick is external defined in file1 but internal re-defined in file2, harry is internal defined in file1, but external re-defined in file2. This example illustrates that variables with external linkage and internal linkage with the same name don‘t conflict with each other.


9.2.6 Static storage duration, no linkage

When you use it within a block, static causes a local variable to have static storage duration, which means that though the variable is only known within that block, it exists while the block is inactive.
The program only initialize a static local variable once, subsequent calls to the function don‘t reinitialize it.
Example comes:

// static.cpp -- using a static local variable
#include <iostream>
const int ArSize = 10;
void strcount(const char * str);

int main()
{
    using namespace std;
    char input[ArSize];
    char next;
    cout << "Enter a line:\n";
    cin.get(input, ArSize);
    while (cin)
    {
        cin.get(next);
        while (next != ‘\n‘)
            cin.get(next);
        strcount(input);
        cout << "Enter next line(empty line to quit):\n";
        cin.get(input, ArSize);
    }
    cout << "Bye\n";
    return 0;
}

void strcount(const char * str)
{
    using namespace std;
    static int total = 0; // static local variable
    int count = 0;
    cout << "\"" << str << "\" contains ";
    while (*str++)
        count++;
    total += count;
    cout << count << " characters\n" << total << " characters total\n";
}

In the example of string-length calculation, the total in strcount() is declared to be static, which means that every time calling the strcount() won‘t cause total to be reinitialized, so total acts as a acumulating variable here.


9.2.7 Specifiers and qualifiers

) storage class specifiers

List of storage class specifiers:
specifier|feature
---|---:
auto|prior to C++11, auto indicates that a variable is a automatic variable
register|indicate register storage class, in C++11 simply indicate automatic variable
static|used with file-scope declaration indicates internal linkage, used with local declaration indicates static storage duration
extern|indicates a reference declaration, that is, the declaration refers to a variable defined elsewhere
thread_local|the duration of the variable is the duration of the containing thread
mutable|explained in terms of const

)Cv-qualifiers

const: It indicates that after initialization, the memory should not be altered by a program
volatile: indicates that the value in a memory location can be altered even if no code modifies it. The intent of this keyword is to improve the optimization process of the compiler. When you use a variable for a number of times, the compiler will take it for granted that the value would not change between the places of access if no code explicitly alter the content. Under this circumstance, the compiler will cache the value in a register so later access would be quicker. But in real conditions, such as calling the system time, no code modifies system time but it actually changes between different accesses. So you could declare a variable as volatile, thus the compiler would not make this sort of optimization.

)mutable

You use mutable to indicate that a particular member of a structure or class can be altered even if the structure is const. Example:

struct data
{
    char name[30];
    mutable int accesses;
    ...
};
const data veep = {"fsb", 0, ...};
strcpy(veep.name, "Joye Joux"); // not allowed because veep.name is in a const structure
veep.accesses++; // allowed
>)**more about const**

**A const global variable has internal linkage on default.** Example:

const int fingers = 10; // same as static const int fingers = 10;

This features makes life easier for you to avoid violating the "one definition rule". Thus, to share constant between different files, you had better write it in a header file and include the header file in each file that you use the set of constants.
You could also override the default behavior to make const global variables to have external linkage by using the keyword extern:

extern const int fingers = 10; // definition of const with external linkage


9.2.8 Funtions and linkage

Functions naturally have static storage duration and external linkage.
You could use the keyword static to give a function internal linkage, confining its use to a single file:

static int private(double x)
{
    ...
}

This means that you could use static functions with the same name in different files. As with variables, a static function overrides an external definition for the file containing the static function.
When you declare a function sharing same name with a standard library function, the compiler uses your version rather than the library version.


9.2.9 Language linking

) C language linkage

C doesn‘t allow functions sharing the same name, so a C compiler might translate a function named spiff to **_spiff**

) C++ language linkage

C++ uses name decoration. It may convert spiff(int) to **_spiff_i** and spiff(double, double) to **_spiff_d_d**

When you want to use a function from a C library in a C++ program, to avoid function-linkage matching problems, you could use the function prototype to explicitly tell the compiler which protocol to use:

extern "C" void spiff(int); // use C protocol for name look-up
extern void spoff(int); // use C++ protocol for name look-up
extern "C++" void spaff(int); // use C++ protocol for name look-up

Cpp Chapter 9: Memory Models and Namespaces Part2

标签:oid   names   repo   hat   als   better   with   one   port   

原文地址:https://www.cnblogs.com/fsbblogs/p/9745910.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!