您的位置:首页 > 编程语言 > C语言/C++

C++11 与 C99的兼容

2016-03-06 17:05 501 查看
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;
}


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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: