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

相关文章

C++中全局变量和局部变量的区别

《C++中全局变量和局部变量的区别》本文主要介绍了C++中全局变量和局部变量的区别,全局变量和局部变量在作用域和生命周期上有显著的区别,下面就来介绍一下,感兴趣的可以了解一下... 目录一、全局变量定义生命周期存储位置代码示例输出二、局部变量定义生命周期存储位置代码示例输出三、全局变量和局部变量的区别作用域

C++中assign函数的使用

《C++中assign函数的使用》在C++标准模板库中,std::list等容器都提供了assign成员函数,它比操作符更灵活,支持多种初始化方式,下面就来介绍一下assign的用法,具有一定的参考价... 目录​1.assign的基本功能​​语法​2. 具体用法示例​​​(1) 填充n个相同值​​(2)

c++ 类成员变量默认初始值的实现

《c++类成员变量默认初始值的实现》本文主要介绍了c++类成员变量默认初始值,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录C++类成员变量初始化c++类的变量的初始化在C++中,如果使用类成员变量时未给定其初始值,那么它将被

C++中NULL与nullptr的区别小结

《C++中NULL与nullptr的区别小结》本文介绍了C++编程中NULL与nullptr的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编... 目录C++98空值——NULLC++11空值——nullptr区别对比示例 C++98空值——NUL

C++ Log4cpp跨平台日志库的使用小结

《C++Log4cpp跨平台日志库的使用小结》Log4cpp是c++类库,本文详细介绍了C++日志库log4cpp的使用方法,及设置日志输出格式和优先级,具有一定的参考价值,感兴趣的可以了解一下... 目录一、介绍1. log4cpp的日志方式2.设置日志输出的格式3. 设置日志的输出优先级二、Window

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

c++中的set容器介绍及操作大全

《c++中的set容器介绍及操作大全》:本文主要介绍c++中的set容器介绍及操作大全,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录​​一、核心特性​​️ ​​二、基本操作​​​​1. 初始化与赋值​​​​2. 增删查操作​​​​3. 遍历方

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决