【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
微信公众号:马志峰的编程笔记
记录一名普通程序员的成长之路



浙公网安备 33010602011771号