C++11 与 C99的兼容

2023-10-11 05:08
文章标签 c++ 兼容 c99

本文主要是介绍C++11 与 C99的兼容,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C++对以下C99特性的支持纳入了新标准之中:
1、C99中的预定义宏
2、__func__预定义标识符
3、_Pragma操作符
4、不定参数宏定义以及__VA_ARGS__
5、宽窄字符串连接



1> c++11中与c99兼容的宏如下表所示:


使用上述宏可以检查机器环境对C标准和C库的支持情况。
#include <iostream>
using namespace std;int main()
{cout << "Standerd Clib" << __STDC_HOSTED__ << endl;cout << "Standerd C" << __STDC__ << endl;//cout << "C Standerd version " << __STDC_VERSION__ << endl;//cout << "ISO/IEC" << __STDC_ISO_10646__ << endl;return 0;
}
在g++ 2.3.3版本中后面两行不能编译通过,说明在g++ 2.3.3版本中可能没有给出这两个宏的定义。

2> __func__预定义标识符

很多现实的编译器都支持C99标准中的__func__预定义标识符功能,其基本功能就是返回所在函数的名字。
#include <iostream>
using namespace std;const char* hello()
{return __func__;
}const char* world()
{return __func__;
}int main()
{cout << hello() << world() << endl;return 0;
}

Tips: vs2012中不支持,g++ 3.3.2版本支持,这个版本的g++还不支持C++11标准。所以这是兼容C99标准。

__func__在按照标准定义,编译器会隐式地在函数定义后面定义__func__标识符。

const char* hello()
{static const char* __func__ = "hello";renturn __func__;
}

在C++11标准中,还允许在类和结构体中使用这个宏。
#include <iostream>
using namespace std;struct TestStruct
{TestStruct(): name(__func__){}const char* name;
};int main()
{TestStruct ts;cout << ts.name << endl;renturn 0;
}

但是将__func__标识符作为函数参数的默认值是不允许的。
void FuncFail(string func_name = __func__){};  //编译不能通过



3>_Pragma操作符

在C/C++标准中,#pragma是一条预处理指令。


#pragma once

上述代码和
#ifndef THIS_HEADER
#define THIS_HEADER//一些头文件定义#endif

C++11中定义一个_Pragma操作符和#pragma作用相同。_Pragma操作符的格式如下:
_Pragma(字符串字面量)
使用_Pragma操作符想要达到#pragma once的效果可以:
_Pragma("once")


4>变长参数的宏定义以及__VA_ARGS__

在C99标准中,程序员可以使用变长参数的宏定义。变长参数的宏定义是指在宏定义中参数列表的最后一个参数为省略号,而预定义宏__VA_ARGS__则可以在宏定义的实现部分替换省略号所代表的字符串。
#define PR(...) printf(__VA__ARGS__)
就可以定义一个printf的别名PR。事实上,变长参数宏和printf是一对好搭档。

#include <stdio.h>#define LOG(...) {\fprintf(stderr,"%S:Line %d:\t"), __FILE__, __LINE__};\fprintf(stderr,__VA__ARGS__);\fprintf(stderr,"\n");\
}int main()
{int x=3;LOG("x=%d",x);
}

上述例子在vs2012中不支持,在g++ 3.3.2版本支持


5>宽窄字符串连接

在C++11中,在将窄字符串和宽字符串进行连接时,支持C++11标准的编译器会将窄字符串转换成宽字符串,然后再与宽字符串进行连接。


6、扩展的整型
C++11中一共只定义了5种标准的有符号整型:
signed char
short int
int
long int
long long int

标准同时规定,每一种有符号整型都有一种对应的无符号整型版本,而且有符号整型与其对应的无符号整型具有相同的存储空间大小。



7、宏__cplusplus
在C/C++混合编写的代码中,我们经常会在头文件中看到如下的声明:

#ifdef __cplusplus
extern "C"{
#endif
//一些代码
#ifdef __cplusplus
}
#endif
由于extern "C"可以抑制C++对函数名、变量名等符号进行名称重整(name mangling),因此编译出的C目标文件中的变量,函数名称等等符号都是相同的,连接器可以
可靠的对两种类型的目标文件进行连接,这样该做法成为C与C++混用头文件的典型做法。
tips:在C++03标准中,__cplusplus的值被预定为199711L,在C++11中,宏__cplusplus被预定义成201103L。那么可以利用这个宏来检查编译器是否支持C++11新标准。


#if __cplusplus < 20131103L#error "should use C++ 11 implementation"
#endif

这里,使用了预处理指令#error,使得不支持C++11时,编译报错并且终止编译。

3、断言assert
assert是一种边编程中常用的手段。用于排除在逻辑上不应该产生的情况。在C++中标准在<cassert>或者<assert.h>头文件中为程序员提供了assert宏,用于在运行时进行断言。


#include <cassert>using namespace std;double div(double a,double b)
{assert(b != 0.000000);  //断言除数必须不为零return a/b;
}int main()
{double rt = div(10,0);return 0;
}

static_assert在C++11中定义了一个static_assert,这个声明对于模板的调试非常有用,编译器快速执行这个常量表示式参数(不能依赖模板参数)。否则编译器当模板实例化时执行这个常量表达式的参数。

#include <cassert>
#include <cstring>
using namespace std;template<typename t, typename u>
int bit_copy(t& a, u& b)
{static_assert(sizeof(b) == sizeof(a), "the parameters of bit_copy must have same width.");
};int main() {int a = 0x2468;double b;bit_copy(a,b);return 0;
}

在编译的过程中就会出现如下的错误信息:






这篇关于C++11 与 C99的兼容的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/185728

相关文章

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

C/C++错误信息处理的常见方法及函数

《C/C++错误信息处理的常见方法及函数》C/C++是两种广泛使用的编程语言,特别是在系统编程、嵌入式开发以及高性能计算领域,:本文主要介绍C/C++错误信息处理的常见方法及函数,文中通过代码介绍... 目录前言1. errno 和 perror()示例:2. strerror()示例:3. perror(

C++变换迭代器使用方法小结

《C++变换迭代器使用方法小结》本文主要介绍了C++变换迭代器使用方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、源码2、代码解析代码解析:transform_iterator1. transform_iterat

详解C++中类的大小决定因数

《详解C++中类的大小决定因数》类的大小受多个因素影响,主要包括成员变量、对齐方式、继承关系、虚函数表等,下面就来介绍一下,具有一定的参考价值,感兴趣的可以了解一下... 目录1. 非静态数据成员示例:2. 数据对齐(Padding)示例:3. 虚函数(vtable 指针)示例:4. 继承普通继承虚继承5.

C++中std::distance使用方法示例

《C++中std::distance使用方法示例》std::distance是C++标准库中的一个函数,用于计算两个迭代器之间的距离,本文主要介绍了C++中std::distance使用方法示例,具... 目录语法使用方式解释示例输出:其他说明:总结std::distance&n编程bsp;是 C++ 标准

C++ 中的 if-constexpr语法和作用

《C++中的if-constexpr语法和作用》if-constexpr语法是C++17引入的新语法特性,也被称为常量if表达式或静态if(staticif),:本文主要介绍C++中的if-c... 目录1 if-constexpr 语法1.1 基本语法1.2 扩展说明1.2.1 条件表达式1.2.2 fa

C++中::SHCreateDirectoryEx函数使用方法

《C++中::SHCreateDirectoryEx函数使用方法》::SHCreateDirectoryEx用于创建多级目录,类似于mkdir-p命令,本文主要介绍了C++中::SHCreateDir... 目录1. 函数原型与依赖项2. 基本使用示例示例 1:创建单层目录示例 2:创建多级目录3. 关键注

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa

C++字符串提取和分割的多种方法

《C++字符串提取和分割的多种方法》在C++编程中,字符串处理是一个常见的任务,尤其是在需要从字符串中提取特定数据时,本文将详细探讨如何使用C++标准库中的工具来提取和分割字符串,并分析不同方法的适用... 目录1. 字符串提取的基本方法1.1 使用 std::istringstream 和 >> 操作符示