assert宏实现中cast-to-void 以及 sizeof 的应用

一: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/

猜你喜欢

转载自blog.csdn.net/u012138730/article/details/80311177