一:cast-to-void应用
vs的警告等级 设置为 level4(项目 右键-->属性-->C++-->常规-->警告等级)C++优化 设置为 禁用(项目 右键-->属性-->C++-->优化-->优化=禁用Od)
1.变量有未使用的警告
编译以下代码
int main() {
int x = 0;
return 0;
}
提示warning,x初始化了没有使用。
1>------ 已启动生成: 项目: zigzag, 配置: Debug Win32 ------
1> main.cpp
1>h:\vs_project\zigzag\zigzag\zigzag\main.cpp(9): warning C4189: “x”: 局部变量已初始化但不引用
========== 生成: 成功 1 个,失败 0 个,最新 0 个,跳过 0 个 ==========
2.转换为void后警告消失
加一句把x强制转换成void类型
int main() {
int x = 0;
(void)x;
return 0;
}
已经没有警告了(看反汇编 忽略了( (void)x )
1>------ 已启动生成: 项目: zigzag, 配置: Debug Win32 ------
1> main.cpp
========== 生成: 成功 1 个,失败 0 个,最新 0 个,跳过 0 个 ==========
强制转换为void是一种在C和C ++中明确忽略变量的惯用方式。
3.cast to 其他类型呢
在vs2015中 也是没有任何警告。(看反汇编 忽略了(short)x)
int main() {
int x = 0;
(short)x;
return 0;
}
1>------ 已启动生成: 项目: zigzag, 配置: Debug Win32 ------
1> main.cpp
========== 生成: 成功 1 个,失败 0 个,最新 0 个,跳过 0 个 ==========
但在这篇文章说 在gcc中这么写,会出现另外一种警告,但是转化了void 类型就不会出现警告。
二:sizeof的应用
看如果是对 函数调用的结果 进行 cast to 其他类型会怎么样。
1.当C++优化设置为禁用:会对函数进行调用
(项目 右键-->属性-->C++-->优化-->优化=禁用Od)
bool isTrue()
{
return false;
}
int main() {
(void)(isTrue()); // 汇编语言 会进行 call isTrue
(int)(isTrue()); // 汇编语言 会进行 call isTrue
return 0;
}
int main() {
01022930 push ebp
01022931 mov ebp,esp
01022933 sub esp,0C0h
01022939 push ebx
0102293A push esi
0102293B push edi
0102293C lea edi,[ebp-0C0h]
01022942 mov ecx,30h
01022947 mov eax,0CCCCCCCCh
0102294C rep stos dword ptr es:[edi]
(void)(isTrue()); // 汇编语言 会进行 call isTrue
0102294E call isTrue (0102133Eh)
(int)(isTrue()); // 汇编语言 会进行 call isTrue
01022953 call isTrue (0102133Eh)
return 0;
01022958 xor eax,eax
}
2.当C++优化设置为O2:不会对函数进行调用
(项目 右键-->属性-->C++-->优化-->优化=速度最大O2)
同时设置基本运行时检查为默认(项目 右键-->属性-->C++-->代码生成-->基本运行时检查=默认值)
反汇编:忽略这这两句话。
--- h:\vs_project\zigzag\zigzag\zigzag\main.cpp --------------------------------
(void)(isTrue());
(int)(isTrue());
return 0;
002916E0 xor eax,eax
}
3.当IsTrue中有其他操作,那么优化设置为O2也是会对函数进行调用
源代码:(注意上一个函数IsTrue中 只有return false,可以被优化,而现在有输出操作)
bool isTrue()
{
std::cout << "aaa" << std::endl;
return false;
}
int main() {
(void)(isTrue());
(int)(isTrue());
return 0;
}
反汇编:执行了isTrue函数
--- h:\vs_project\zigzag\zigzag\zigzag\main.cpp --------------------------------
(void)(isTrue());
00B91B90 push offset std::endl<char,std::char_traits<char> > (0B9105Fh)
00B91B95 push offset string "aaa" (0B96B30h)
00B91B9A push dword ptr [_imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A (0B99070h)]
00B91BA0 call std::operator<<<std::char_traits<char> > (0B9129Eh)
00B91BA5 add esp,8
00B91BA8 mov ecx,eax
00B91BAA call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0B9906Ch)]
(int)(isTrue());
00B91BB0 push offset std::endl<char,std::char_traits<char> > (0B9105Fh)
00B91BB5 push offset string "aaa" (0B96B30h)
00B91BBA push dword ptr [_imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A (0B99070h)]
00B91BC0 call std::operator<<<std::char_traits<char> > (0B9129Eh)
00B91BC5 add esp,8
00B91BC8 mov ecx,eax
00B91BCA call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0B9906Ch)]
return 0;
00B91BD0 xor eax,eax
}
4.如果让加上sizeof,不论C++优化设置如何以及函数内容如何:都不会对函数进行调用
为什么是sizeof操作符:
if only there were some C++ keyword that could syntactically accept almost anything and be guaranteed not to emit any code.
The operand is either an expression, which is not evaluated, or a parenthesized type-id.
源代码:、
bool isTrue()
{
std::cout << "aaa" << std::endl;
return false;
}
int main() {
(void)sizeof((isTrue()));
(int)sizeof((isTrue()));
return 0;
}
反汇编:没有对函数进行调用,直接忽略了这两句。
--- h:\vs_project\zigzag\zigzag\zigzag\main.cpp --------------------------------
(void)sizeof((isTrue()));
(int)sizeof((isTrue()));
return 0;
00861B90 xor eax,eax
}
三:assert的宏实现(关注当走#else 分支的时候)
1.会出现警告版:#define POW2_ASSERT(x)
#ifdef POW2_ASSERTS_ENABLED
#define POW2_ASSERT(x) \
do { if (!(x)) { pow2::Assert::Fail(#x, __FILE__, __LINE__); } } while(0)
#else
#define POW2_ASSERT(x)
#endif
2.消除警告版:#define POW2_ASSERT(x) do { (void)(x); } while(0) ,但...
取决于编译器优化设置以及x的内容
如果x是函数调用,且函数内容不可被优化,那么会进行本意 不想被调用执行的函数 被调用执行。
#ifdef POW2_ASSERTS_ENABLED
#define POW2_ASSERT(x) \
do { if (!(x)) { pow2::Assert::Fail(#x, __FILE__, __LINE__); } } while(0)
#else
#define POW2_ASSERT(x) \
do { (void)(x); } while(0)
#endif
3.最终版:#define POW2_ASSERT(x) do { (void)sizeof(x); } while(0)
#ifdef POW2_ASSERTS_ENABLED
#define POW2_ASSERT(x) \
do { if (!(x)) { pow2::Assert::Fail(#x, __FILE__, __LINE__); } } while(0)
#else
#define POW2_ASSERT(x) \
do { (void)sizeof(x); } while(0)
#endif
参考资料
http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/