【Json11源码阅读】03 问题解答,Part_1
问题1
#pragma once
疑问
这个宏相当于头文件保护?完全等价吗?
解题思路
百度
解答
#pragma once
是编译器相关的,有的编译器支持,有的编译器不支持#ifndef
,#define
,#endif
是C/C++
语言中的宏定义,通过宏定义避免文件多次编译。所以在所有支持C++语言的编译器上都是有效的,如果写的程序要跨平台,最好使用这种方式。
参考资料
问题2
#ifdef _MSC_VER
#if _MSC_VER <= 1800 // VS 2013
#ifndef noexcept
#define noexcept throw()
#endif
#ifndef snprintf
#define snprintf _snprintf_s
#endif
#endif
#endif
疑问
这里的define有什么用途?
解题思路
首先需要弄明白noexcept
的用途,尝试在c++ Primer
中找到相关章节
- 翻目录,没找到
- 翻目录后的
c++11的新特性
- 13.6.2 移动构造函数通常应该是noexcept
- 18.1.4 noexpect异常指示符
- 18.1.4 noexpect运算符
P690可以解答我们的疑问
解答
noexpect
说明,用于告诉用户和编译器这个函数不会抛出异常
- 用户知道这个信息有助于简化调用该函数的代码
- 编译器知道这个信息能执行某些特殊的优化操作
noexcept
紧跟在函数的参数列表后面,用以标识该函数不会抛出异常
如果对函数进行了noexpect
说明,却在函数内部执行throw
语句或调用可能抛出异常的函数,程序会终止执行以确保遵守不在运行时抛出异常的承诺
noexpect
说明符接受一个可选的实参,该实参必须能转换为bool
类型
void recoup(int) noexpect(true);
void alloc(int) noexpect(false);
实参为true
时指明函数不会抛出异常,为false
时则可能抛出异常。看上去有点多此一举,不带参也能完成说明,那为什么要支持带参呢?
猜想应该是支持表达式的
果然,还提供了noexpect
运算符。
noexpect(e)
如果e调用的所有函数都进行了noexpect
说明且e本身不含有throw
语句时,返回true
void f() noexpect(noexpect(g()));
后面一个noexpect
运算符的返回值作为前一个noexpect
说明符的实参
回到问题本身,很容易看出vs2013之前的版本可能没有定义noexpect
。因此这里的define
使用等价语句throw()
来解决这个问题
同样的,如果没有定义snprintf
,就使用_snprintf_s
来替代
那么snprintf
是什么意思呢?
- 照旧去书上找找看,没找到。
- cppreference是第二选择
http://www.cplusplus.com/reference/cstdio/snprintf/
可以看到,snprintf
也是c++11提供的一个方法,定义在头文件<cstdio>
中
int snprintf ( char * s, size_t n, const char * format, ... );
它的作用就是:Write formatted output to sized buffer
将格式化的输出写入到指定大小的内存中
s用于缓存输出的内存
n指定最大允许使用s中多大的内存,超出的文本会被丢弃
format是带格式的文本
示例:
char buffer [100];
int cx;
cx = snprintf ( buffer, 100, "The half of %d is %d", 60, 60/2 );
format中包含多少个格式化字符,后面就需要跟多少个表达式
返回值是本次输出共使用了多少内存
PS: 如果有书介绍这部分内容欢迎指出。
参考资料
《c++ primer(第五版)》
P690- http://www.cplusplus.com/reference/cstdio/snprintf/
END
微信公众号:马志峰的编程笔记
记录一名普通程序员的成长之路