C++

C++ 知识量:19 - 82 - 316

19.6 固有的不可移植的特性><

不可移植的特性- 19.6.1 -

不可移植的特性是指因机器而异的特性,当将含有不可移植特性的程序从一台机器转移到另一台机器上时,通常需要重新编写该程序。C++有一些固有的不可移植特性:

  1. 平台特定的代码:C++允许直接调用特定于平台的代码。例如,可以直接访问在某些平台上可用的特定CPU寄存器或指令集。这种代码在非目标平台上将无法运行。

  2. 编译器特定的代码:C++编译器可以生成特定的代码,这些代码依赖于特定编译器的实现。例如,某些编译器可能会使用特定的优化策略或特定的指令集。

  3. 依赖实现的代码:C++标准并没有规定所有的实现细节,因此,依赖于这些细节的代码就是不可移植的。例如,两个不同的C++编译器可能会有不同的内存布局和对对象生命周期的处理方式。

  4. 对硬件的直接访问:C++允许直接访问硬件资源,如内存、I/O端口等。这种代码在硬件环境不同的系统上将无法运行。

  5. 宏和预处理器指令:宏和预处理器指令在C++中也是不可移植的,因为它们在编译时被处理,并且其行为可能依赖于特定的编译器和平台。

  6. 非标准库函数:许多非标准库函数也是不可移植的,因为它们可能只在特定的平台或编译器上可用。

C++从C语言继承而来的有两种不可移植的特性:位域和volatile限定符。

位域- 19.6.2 -

位域(bit-field)是一种C++中的数据结构,它允许将一组相关的二进制位(bit)封装成一个逻辑单位。位域通常用于表示一组二进制位,这些位具有特定的含义和约束。

在C++中,可以通过声明类或结构体的成员变量为位域来使用它。位域的声明语法如下:

type name : size;

其中,type是位域的数据类型,可以是unsigned int或signed int;name是位域的名称;size是指定的二进制位数。

例如,如果想要定义一个表示8位二进制数的位域,可以使用以下语法:

class MyClass {  
public:  
    unsigned int myBits : 8;  
};

在这个例子中,myBits是一个8位的位域。可以将这个位域看作是一个只能存储8位二进制数的变量。由于使用了无符号整数类型(unsigned int),因此这个位域只能存储0到255之间的值。

使用位域的好处之一是它可以有效地利用内存空间。由于位域只占用指定数量的二进制位,因此它可以减少内存的使用量。此外,位域还可以方便地操作和管理一组相关的二进制位。

在实际应用中,位域通常用于以下几个方面:

  1. 结构体打包:当需要将一组相关的二进制位打包成一个结构体或类时,可以使用位域来实现。这样可以减少结构体或类的内存占用。

  2. 硬件寄存器映射:在嵌入式系统或驱动程序开发中,经常需要直接操作硬件寄存器。使用位域可以方便地映射硬件寄存器的每一位到程序中的变量。

  3. 网络通信协议:在网络通信中,经常需要传输二进制数据。使用位域可以方便地定义网络协议中的数据格式,并在程序中操作这些数据格式。

volatile限定符- 19.6.3 -

volatile是C++中的一个类型修饰符,用于告诉编译器该变量可能会被意想不到地修改,因此编译器不应对这种变量进行优化。

例如,在多线程编程中,如果一个变量可能会被多个线程同时修改,那么就需要将其声明为volatile。这样,每次编译器看到对这个变量的引用时,都会确保它从内存中获取最新的值,而不是使用保存在寄存器中的备份。

另一个使用volatile的情况是访问硬件寄存器。例如,可能编写直接访问硬件的代码,此时需要将某些变量声明为volatile,以便编译器不会优化这些变量,从而避免产生不可预见的副作用。

但是请注意,volatile并不能解决所有的并发问题。在多线程环境下,仍然需要使用适当的同步机制(如互斥锁或信号量)来确保线程安全。

下面是一个使用volatile的例子:

volatile int x = 0; // 这个变量可能会被意想不到地修改

在这个例子中,变量x被声明为volatile,这意味着编译器不会认为它只会在程序的正常执行过程中被修改。因此,每次引用x时,编译器都会从内存中获取它的最新值,而不是使用保存在寄存器中的备份。

链接指示- 19.6.4 -

在C++中,链接指示(linkage directive)是一种特殊的指令,用于指定变量或函数的链接属性。链接属性决定了变量或函数在程序中的可见性和共享性。

C++中的链接指示有两种类型:外部链接指示(extern linkage)和内部链接指示(internal linkage)。

1. 外部链接指示(extern linkage):当变量或函数被声明为extern时,它具有外部链接属性。这意味着该变量或函数在整个程序中是可见的,并且可以在多个编译单元(即源文件)之间共享。使用extern关键字可以声明在其他编译单元中定义的变量或函数,以便在当前编译单元中引用它们。例如:

extern int globalVariable; // 声明一个在其他编译单元中定义的全局变量      
extern void someFunction(); // 声明一个在其他编译单元中定义的函数

2. 内部链接指示(internal linkage):当变量或函数没有被声明为extern时,它具有内部链接属性。这意味着该变量或函数只在当前编译单元中可见,不能在其他编译单元中直接引用。内部链接的变量或函数在每个编译单元中都有独立的实例,它们之间不会共享数据。例如:

static int staticVariable; // 声明一个具有内部链接属性的静态变量      
static void staticFunction(); // 声明一个具有内部链接属性的静态函数

在上述示例中,使用static关键字可以将变量或函数声明为具有内部链接属性。这意味着它们只在当前编译单元中可见,并且每个编译单元中的实例都是独立的。

链接指示对于程序的组织和模块化非常重要。通过使用外部链接指示,可以在多个源文件之间共享变量和函数的定义,从而实现代码的重用和模块化。而通过使用内部链接指示,可以隐藏实现细节,并限制变量和函数的可见性范围,从而提高代码的可维护性和安全性。