2000年至今,由于以Loki、MPL(Boost)等程序库为代表的产生式编程和模板元编程的出现,C++出现了发展历史上又一个新的高峰,这些新技术的出现以及和原有技术的融合,使C++已经成为当今主流程序设计语言中最复杂的一员-维基百科C++词条

丰富的程序库以及本身的语言特性,使得C++在开发效率和运行效率上有着不错平衡,但这同时也增加了学习C++所带来的时间成本,C++疑问集此系列用于记录笔者学习C++路上遇到的问题,对部分易于混淆的知识点加以总结与汇总,以便于读者对C++有更深入的了解。

十进制浮点数的二进制存储方式以及转换

V = (-1)^s×M×2^E

  • (-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数
  • M表示有效数字,大于等于1,小于2
  • 2^E表示指数

例如:将十进制178.125表示成机器内的32个字节的二进制形式

  • 第一步:将178.125表示成二进制数:(178.125)(十进制数)=(10110010.001)(二进制形式);

十进制整数转换为二进制整数:==除2取余,逆序排列==
十进制小数转换为二进制小数:==乘2取整,顺序排列==

  • 第二步:将二进制形式的浮点实数转化为规格化的形式:(小数点向左移动7个二进制位可以得到)

10110010.001=1.0110010001*2^7 因而产生了以下三项:

  • 符号位:该数为正数,故第31位为0,占一个二进制位
  • 阶码:指数为7,故其阶码为127+7=134=(10000110)(二进制),占从第30到第23共8个二进制位
  • 尾数:为小数点后的部分, 即0110010001.因为尾数共23个二进制位,在后面补13个0,即01100100010000000000000

所以178.125在内存中的实际表示方式为:
0|10000110 |01100100010000000000000

cerr、cout、clog的区别

  • cout:标准输出流,用于常规输出,输入读进缓冲区,触发刷新缓冲区动作时输出缓冲区内容至终端显示器,也可被重定向输出至磁盘文件
  • cerr:非缓冲的标准错误流,用于显示错误信息,错误信息不输入缓冲区,直接显示在终端显示器,一般情况下不被重定向
  • clog:缓冲的标准错误流,一般用于记录运行日志,日志消息读进缓冲区,触发刷新缓冲区动作时输出缓冲区内容至终端显示器,一般情况下可被重定向输出至日志文件

tip:重定向在不同的操作环境定义不同

缓冲区的作用:计算机对缓冲区的操作快于磁盘操作,可以减少计算机对磁盘的读写次数,对低速的输入输出设备和高速的CPU之间进行协调工作。

触发刷新缓冲区的动作

  1. 缓冲区满时
  2. 执行flush语句
  3. 行缓冲时遇到endl,cerr或cin时
  4. 关闭文件

cerr与clog的使用场景

  • clog:clog为缓冲输出,cerr为无缓冲输出,缓冲输出通常比无缓冲效率高,所以记录日志一般使用clog
  • cerr:由于clog为缓冲输出,当程序崩溃时,如果所有日志信息以及错误信息都使用clog来输出,因为程序崩溃可能导致的缓冲区丢失,则可能看不到所有的信息。因此,我们一般使用cerr来输出错误信息,当程序崩溃时,由于cerr为无缓冲输出,则不会出现因为缓冲区丢失而导致的信息缺失的情况

C++ typedef的使用场景

  1. 定义类型的别名(区分#define的宏替换)
    例子:
    1
    2
    3
    4
    typedef char *pStr1;
    #define pStr2 char *;
    pStr1 s1, s2; //s1,s2为char*类型
    pStr2 s3, s4; //s3为char*类型,s4为char类型

注意:#define进行的宏替换类似于简单的replace操作,typedef相当于定义新的类型,编译器编译时会将typedef定义的类型认定为新的类型,详情见下方例子

1
2
3
4
5
6
7
8
typedef char* pStr;
#define pStr1 char* ;
const char* p1 = "hello";
const pStr p2 = "hello";
const pStr1 p3 = "hello";
p1++;//正常,常量指针是可变的
p2++;//报错,系统将pStr认定为常量的新类型,常量不可修改
p3++;//正常,#define进行的是简单的文本替换,pStr1还是常量指针
  1. 定义struct结构体别名
    例子:
    1
    2
    3
    4
    5
    6
    typedef struct tagPOINT  
    {
    int x;
    int y;
    }POINT;
    POINT p1; //省略了struct
  2. 定义多平台应用类型
    例子:
    定义浮点类型为REAL,只需要修改typedef就可以在多个平台使用REAL来定义浮点类型变量
    平台一支持long与double类型:typedef long double REAL;
    平台二支持long类型:typedef long REAL;
    平台三long与double类型都不支持:typedef float REAL;

注意:typedef跟static和register等存储类关键字一样,所以一行typedef声明中不能出现其他的存储类关键字(编译错误:typedef static int A;)
4. 简化复杂的变量声明
例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<iostream>
using namespace std;
typedef int A(char a,char b); //定义函数A,包含两个char类型形参,返回int类型值

class X{
public:A(fun); //函数声明,等价于int fun(char a,char b);
};

int X::fun(char a,char b){
cout<<"succcess"<<endl;
return 0;
}

int main()
{
X *xx;
xx->fun('a','b');
return 0;
}

Java与C++的成员和类的默认访问修饰符?

  • Java:接口的默认修饰符为public;类的默认修饰符为default(整个包内都可以被访问)
  • C++:类的默认修饰符为private(变量或函数在类的外部不可访问),而struct中则是public

才学疏浅,欢迎评论指导

评论