当前位置:编程学习 > C/C++ >>

【Deep C (and C++)】深入理解C/C++(3)

译自Deep C (and C++) by Olve Maudal and Jon Jagger,本身半桶水不到,如果哪位网友发现有错,留言指出吧:)

 

第二位候选者表现不错,那么,相比大多数程序员,他还有什么潜力没有被挖掘呢?

可以从以下几个角度去考察:

有关平台的问题—32位与64位的编程经验;

内存对齐;

CPU以及内存优化;

C语言的精髓;

 

接下来,主要分享一下以下相关内容:

内存模型;

优化;

C语言之精髓;

 

 

内存模型:

静态存储区(static storage):如果一个对象的标识符被声明为具有内部链接或是外部链接,或是存储类型说明符是static,那么这个对象具有静态生存期。这个对象的生命周期是整个程序的运行周期。

PS:内部链接,也就是编译单元内可见,是需要使用static来修饰的,连接程序不可见;外部链接,是指别的编译单元可见,也就是链接程序可见。我这里还不太清楚为什么需要三种情况来说明。


int* immortal(void) 

    static int storage = 42; 
    return &storage; 

 

自动存储区(automatic storage):如果一个对象没有被指明是内部链接还是外部链接,并且也没有static修饰,那么,这个对象具有自动生存期,也称之为本地生存期。一般使用auto说明符来修饰,只在块内的变量声明中允许使用,这样是默认的情况,因此,很少看到auto说明符。简单地说,自动存储区的变量,在一对{}之间有效。


int* zombie(void) 

    auto int storage = 42; 
    return &storage; 

分配的存储区域(allocated storage):调用calloc函数,malloc函数,realloc函数分配的内存,称之为分配的存储区域。他们的作用域(生命周期会是更好的术语吗?)在分配和释放之间。

 

int* finite(void) 

    int* ptr = malloc(sizeof(int*)); 
    *ptr = 42; 
    return ptr; 

 

优化相关:

一般来说,编译的时候,你都应该打开优化选项。强制编译器更努力的去发现更多的潜在的问题。


上面,同样地代码,打开优化选项的编译器得到了警告信息:a 没有初始化。

 \

C语言的精髓:

C语言的精髓体现在很多方面,但其本质在于一种社区情感(communitysentiment),这种社区情感建立在C语言的基本原则之上。

C语言原理简介:

1、  相信程序员;

2、  保持语言简单精炼;

3、  对每一种操作,仅提供一种方法;(译者注:?)

4、  尽可能的快,但不保证兼容性;

5、  保持概念上的简单;

6、  不阻止程序员做他们需要做的事。

 

 

现在来考察一下我们的候选者关于C++的知识:)

 

你:1到10分,你觉得你对C++的理解可以打几分?

第一个候选者:我觉得我可以打8到9分。

第二个候选者:4分,最多也就5分了。我还需要多加学习C++。

这时,C++之父Bjarne Stroustrup在远方传来声音:我觉得我可以打7分。(OH,MY GOD!!)

 

那么,下面的代码段,会输出什么?


#include <iostream> 
 
struct X 

    int a; 
    char b; 
    int c; 
}; 
 
int main(void) 

    std::cout << sizeof(X) << std::endl; 

 

第二个候选者:这个结构体是一个朴素的结构体(POD:plain old data),C++标准保证在使用POD的时候,和C语言没有任何区别。因此,在你的机器上(64位机器,运行在32位兼容模式下),我觉得会输出12.

顺便说一下,使用func(void)而不是用func()显得有点诡异,因为C++中,void是默认情况,这个相对于C语言的默认是任意多的参数,是不一样的。这个规则同样适用于main函数。当然,这不会带来什么伤害。但这样的代码,看起来就像是顽固的C程序员在痛苦的学习C++的时候所写的。下面的代码,看起来更像C++:


#include <iostream> 
 
struct X 

    int a; 
    char b; 
    int c; 
}; 
 
int main() 

    std::cout << sizeof(X) << std::endl; 

 

第一个候选者:这个程序会打印12.

你:好。如果我添加一个成员函数,会怎么样?比如:


#include <iostream> 
 
struct X 

    int a; 
    char b; 
    int c; 
 
    void set_value(int v) { a = v; } 
}; 
 
int main() 

    std::cout << sizeof(X) << std::endl; 


第一个候选者:啊?C++中可以这样做吗?我觉得你应该使用类(class)。

你:C++中,class和struct有什么区别?

候选者:在一个class中,你可以有成员函数,但是我不认为在struct中可以拥有成员函数。莫非可以?难道是默认的访问权限不同?(Is it the default visibility that is different?)

不管怎样,现在程序会输出16.因为,会有一个指针指向这个成员函数。

你:真的?如果我多增加两个函数呢?比如:


#include <iostream> 
 
struct X 

    int a; 
    char b; 
    int c; 
 
    void set_value(int v) { a = v; } 
    int get_value() { return a; } 
    void increase_value() { a++; } 
}; 
 
int main() 

    std::cout << sizeof(X) << std::endl; 

第一个候选者:我觉得对打印24,多了两个指针?

你:在我的机器上,打印的值比24小。

候选者:啊!对了,当然,这个struct有一个函数指针的表,因此他仅仅需要一个指向这个表的指针!我确实对此有一个很深的理解,我差点忘记了,呵呵。

你:事实上,在我的机器上,这段代码输出了12.

候选者心里犯嘀咕:哦?可能是某些诡异的优化措施在捣鬼,可能是因为这些函数永远不会被调用。

 

你对第二个候选者说:你怎么想的?

第二个候选者:在你的机器上?我觉得还是12?

你:好,为什么?

候选者:因为以这种方式来增加成员函数,不会增加struct的所占内存的大小。对象对他的函数一无所知,反过来,是函数知道他具体属于哪一个对象。如果你把这写成C语言的形式,就会变得明朗起来了。

你:你是指这样的?


struct X 

    int a; 
    char b; 
    int c; 
}; 
 
void set_value(struct X* this, int v) { this->a = v; } 
int get_value(struct X* this) { return this->a; } 
void increase_value(struct X* this) { this->a++; } 

第二个候选者:恩。就想这样的。现在很明显很看出,类似这样的函数是不会增加类型和对象的内存大小的。

 

你:那么现在呢?


#include <iostream> 
 
struct X 

    int a; 
    char b; 
    int c; 
 
    virtual void set_value(int v) { a = v; } 
    int get_value() { return a; } 
    void increase_value() { a++; } 
}; 
 
int main() 

    std::cout << sizeof(X) << std:

补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,