- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
想了解一下GCC编译器在使用noexcept
时生成的分支或 throw()
用于标记非抛出函数。我知道 noexcept
之间的区别和 throw()
, 但无法弄清楚使用 throw()
时定义的附加分支是什么而不是 noexcept
以及如何提高覆盖率以达到 100% 的分支机构覆盖率?
测试示例类的代码片段:
class MyClass
{
public:
MyClass() noexcept :
iThrowFlag(false)
{}
void non_throwing_method() noexcept
{
try
{
throwing_method();
}
catch (...)
{
}
}
void throwing_method()
{
if (iThrowFlag)
{
throw std::exception();
}
}
public:
bool iThrowFlag;
};
定义了 2 个测试用例,都通过了:
non_throwing_method
底层时完成 throwing_method
不扔,non_throwing_method
底层时完成 throwing_method
正在抛出任何异常。下面是 GCC/GCOV 为上述代码生成的覆盖率报告,所有的行和分支都被覆盖了(覆盖了 4/4 个分支):
-: 0:Source:myclass.hh
-: 0:Graph:main.gcno
-: 0:Data:main.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include <iostream>
-: 2:#include <string>
-: 3:
-: 4:using namespace std;
-: 5:
-: 6:class MyClass
-: 7:{
-: 8:public:
function _ZN7MyClassC2Ev called 2 returned 100% blocks executed 100%
2: 9: MyClass() noexcept :
2: 10: iThrowFlag(false)
2: 11: {}
-: 12:
function _ZN7MyClass19non_throwing_methodEv called 2 returned 100% blocks executed 100%
2: 13: void non_throwing_method() noexcept
-: 14: {
-: 15: try
-: 16: {
2: 17: throwing_method();
call 0 returned 100%
branch 1 taken 50% (fallthrough)
branch 2 taken 50% (throw)
-: 18: }
1: 19: catch (...)
call 0 returned 100%
-: 20: {
-: 21: }
2: 22: }
-: 23:
function _ZN7MyClass15throwing_methodEv called 2 returned 50% blocks executed 100%
2: 24: void throwing_method()
-: 25: {
2: 26: if (iThrowFlag)
branch 0 taken 50% (fallthrough)
branch 1 taken 50%
-: 27: {
1: 28: throw std::exception();
call 0 returned 100%
call 1 returned 100%
call 2 returned 0%
-: 29: }
1: 30: }
-: 31:
-: 32:public:
-: 33: bool iThrowFlag;
-: 34:};
由于目标平台不支持 C++11 和 noexcept
, 它被交换为 throw()
说明符如下:
class MyClass
{
public:
MyClass() throw() :
iThrowFlag(false)
{}
void non_throwing_method() throw()
{
try
{
throwing_method();
}
catch (...)
{
}
}
void throwing_method()
{
if (iThrowFlag)
{
throw std::exception();
}
}
public:
bool iThrowFlag;
};
在带有已检查分支的 GCOV 输出下方 (5/8)。用 throw()
编码生成额外的 4 个分支,这些分支很难理解,也很难通过测试覆盖:
-: 0:Source:myclass.hh
-: 0:Graph:main.gcno
-: 0:Data:main.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include <iostream>
-: 2:#include <string>
-: 3:
-: 4:using namespace std;
-: 5:
-: 6:class MyClass
-: 7:{
-: 8:public:
function _ZN7MyClassC2Ev called 2 returned 100% blocks executed 100%
2: 9: MyClass() throw() :
2: 10: iThrowFlag(false)
2: 11: {}
-: 12:
function _ZN7MyClass19non_throwing_methodEv called 2 returned 100% blocks executed 75%
2: 13: void non_throwing_method() throw()
-: 14: {
-: 15: try
-: 16: {
2: 17: throwing_method();
call 0 returned 100%
branch 1 taken 50% (fallthrough)
branch 2 taken 50% (throw)
-: 18: }
1: 19: catch (...)
call 0 returned 100%
call 1 returned 100%
branch 2 taken 100% (fallthrough)
branch 3 taken 0% (throw)
branch 4 never executed
branch 5 never executed
call 6 never executed
-: 20: {
-: 21: }
2: 22: }
-: 23:
function _ZN7MyClass15throwing_methodEv called 2 returned 50% blocks executed 100%
2: 24: void throwing_method()
-: 25: {
2: 26: if (iThrowFlag)
branch 0 taken 50% (fallthrough)
branch 1 taken 50%
-: 27: {
1: 28: throw std::exception();
call 0 returned 100%
call 1 returned 100%
call 2 returned 0%
-: 29: }
1: 30: }
-: 31:
-: 32:public:
-: 33: bool iThrowFlag;
-: 34:};
测试用例如下(以获取有关该用例的完整详细信息):
void test1()
{
MyClass lObj;
lObj.non_throwing_method();
}
void test2()
{
MyClass lObj;
lObj.iThrowFlag = true;
lObj.non_throwing_method();
lObj.iThrowFlag = false;
}
如果有人对所描述的行为有答案/解释,我将不胜感激。
编辑:另附汇编代码(仅函数代码:`non_throwing_method1 进行比较)。
没有异常(exception):
_ZN7MyClass19non_throwing_methodEv:
.LFB1253:
.loc 2 13 0
.cfi_startproc
.cfi_personality 0x3,__gxx_personality_v0
.cfi_lsda 0x3,.LLSDA1253
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movq %rdi, -8(%rbp)
movq __gcov0._ZN7MyClass19non_throwing_methodEv(%rip), %rax
addq $1, %rax
movq %rax, __gcov0._ZN7MyClass19non_throwing_methodEv(%rip)
.loc 2 17 0
movq -8(%rbp), %rax
movq %rax, %rdi
.LEHB0:
call _ZN7MyClass15throwing_methodEv
.LEHE0:
movq __gcov0._ZN7MyClass19non_throwing_methodEv+8(%rip), %rax
addq $1, %rax
movq %rax, __gcov0._ZN7MyClass19non_throwing_methodEv+8(%rip)
.loc 2 22 0
jmp .L7
.L6:
movq %rax, %rdx
movq __gcov0._ZN7MyClass19non_throwing_methodEv+16(%rip), %rax
addq $1, %rax
movq %rax, __gcov0._ZN7MyClass19non_throwing_methodEv+16(%rip)
.loc 2 19 0
movq %rdx, %rax
movq %rax, %rdi
call __cxa_begin_catch
movq __gcov0._ZN7MyClass19non_throwing_methodEv+24(%rip), %rax
addq $1, %rax
movq %rax, __gcov0._ZN7MyClass19non_throwing_methodEv+24(%rip)
call __cxa_end_catch
movq __gcov0._ZN7MyClass19non_throwing_methodEv+32(%rip), %rax
addq $1, %rax
movq %rax, __gcov0._ZN7MyClass19non_throwing_methodEv+32(%rip)
.L7:
.loc 2 22 0
nop
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1253:
.globl __gxx_personality_v0
.section .gcc_except_table._ZN7MyClass19non_throwing_methodEv,"aG",@progbits,_ZN7MyClass19non_throwing_methodEv,comdat
.align 4
.LLSDA1253:
.byte 0xff
.byte 0x3
.uleb128 .LLSDATT1253-.LLSDATTD1253
.LLSDATTD1253:
.byte 0x1
.uleb128 .LLSDACSE1253-.LLSDACSB1253
.LLSDACSB1253:
.uleb128 .LEHB0-.LFB1253
.uleb128 .LEHE0-.LEHB0
.uleb128 .L6-.LFB1253
.uleb128 0x1
.LLSDACSE1253:
.byte 0x1
.byte 0
.align 4
.long 0
.LLSDATT1253:
.section .text._ZN7MyClass19non_throwing_methodEv,"axG",@progbits,_ZN7MyClass19non_throwing_methodEv,comdat
.size _ZN7MyClass19non_throwing_methodEv, .-_ZN7MyClass19non_throwing_methodEv
.section .text._ZN7MyClass15throwing_methodEv,"axG",@progbits,_ZN7MyClass15throwing_methodEv,comdat
.align 2
.weak _ZN7MyClass15throwing_methodEv
.type _ZN7MyClass15throwing_methodEv, @function
使用 throw():
_ZN7MyClass19non_throwing_methodEv:
.LFB1253:
.loc 2 13 0
.cfi_startproc
.cfi_personality 0x3,__gxx_personality_v0
.cfi_lsda 0x3,.LLSDA1253
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movq %rdi, -8(%rbp)
movq __gcov0._ZN7MyClass19non_throwing_methodEv(%rip), %rax
addq $1, %rax
movq %rax, __gcov0._ZN7MyClass19non_throwing_methodEv(%rip)
.loc 2 17 0
movq -8(%rbp), %rax
movq %rax, %rdi
.LEHB0:
call _ZN7MyClass15throwing_methodEv
.LEHE0:
movq __gcov0._ZN7MyClass19non_throwing_methodEv+8(%rip), %rax
addq $1, %rax
movq %rax, __gcov0._ZN7MyClass19non_throwing_methodEv+8(%rip)
.loc 2 22 0
jmp .L3
.L8:
movq %rax, %rdx
movq __gcov0._ZN7MyClass19non_throwing_methodEv+16(%rip), %rax
addq $1, %rax
movq %rax, __gcov0._ZN7MyClass19non_throwing_methodEv+16(%rip)
.loc 2 19 0
movq %rdx, %rax
movq %rax, %rdi
call __cxa_begin_catch
movq __gcov0._ZN7MyClass19non_throwing_methodEv+24(%rip), %rax
addq $1, %rax
movq %rax, __gcov0._ZN7MyClass19non_throwing_methodEv+24(%rip)
.LEHB1:
call __cxa_end_catch
.LEHE1:
movq __gcov0._ZN7MyClass19non_throwing_methodEv+32(%rip), %rax
addq $1, %rax
movq %rax, __gcov0._ZN7MyClass19non_throwing_methodEv+32(%rip)
.loc 2 22 0
jmp .L3
.L9:
cmpq $-1, %rdx
je .L7
movq __gcov0._ZN7MyClass19non_throwing_methodEv+48(%rip), %rdx
addq $1, %rdx
movq %rdx, __gcov0._ZN7MyClass19non_throwing_methodEv+48(%rip)
movq %rax, %rdi
.LEHB2:
call _Unwind_Resume
.L7:
movq __gcov0._ZN7MyClass19non_throwing_methodEv+40(%rip), %rdx
addq $1, %rdx
movq %rdx, __gcov0._ZN7MyClass19non_throwing_methodEv+40(%rip)
.loc 2 13 0
movq %rax, %rdi
call __cxa_call_unexpected
.LEHE2:
.L3:
.loc 2 22 0
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1253:
.globl __gxx_personality_v0
.section .gcc_except_table._ZN7MyClass19non_throwing_methodEv,"aG",@progbits,_ZN7MyClass19non_throwing_methodEv,comdat
.align 4
.LLSDA1253:
.byte 0xff
.byte 0x3
.uleb128 .LLSDATT1253-.LLSDATTD1253
.LLSDATTD1253:
.byte 0x1
.uleb128 .LLSDACSE1253-.LLSDACSB1253
.LLSDACSB1253:
.uleb128 .LEHB0-.LFB1253
.uleb128 .LEHE0-.LEHB0
.uleb128 .L8-.LFB1253
.uleb128 0x1
.uleb128 .LEHB1-.LFB1253
.uleb128 .LEHE1-.LEHB1
.uleb128 .L9-.LFB1253
.uleb128 0x3
.uleb128 .LEHB2-.LFB1253
.uleb128 .LEHE2-.LEHB2
.uleb128 0
.uleb128 0
.LLSDACSE1253:
.byte 0x1
.byte 0
.byte 0x7f
.byte 0
.align 4
.long 0
.LLSDATT1253:
.byte 0
.section .text._ZN7MyClass19non_throwing_methodEv,"axG",@progbits,_ZN7MyClass19non_throwing_methodEv,comdat
.size _ZN7MyClass19non_throwing_methodEv, .-_ZN7MyClass19non_throwing_methodEv
.section .text._ZN7MyClass15throwing_methodEv,"axG",@progbits,_ZN7MyClass15throwing_methodEv,comdat
.align 2
.weak _ZN7MyClass15throwing_methodEv
.type _ZN7MyClass15throwing_methodEv, @function
最佳答案
看来我要过一会儿再回答我自己的问题。
throw()
和 noexcept
之间的区别(从 C++11 到 C++17)非常大。
在运行时,如果异常将函数标记为throw()
调用堆栈展开到函数的调用者,然后调用 std::unexpected
来执行意外处理程序,最后(默认行为)程序由 std::terminate
.
对于 C++11,noexcept 运行时行为略有不同:调用堆栈只是可能在程序执行终止之前展开。没有调用 std::unexpected
。通常编译器只调用 std::terminate
而不会展开。
就是这样,这就是为什么 throw()
和 noexcept
函数生成不同的汇编代码以及代码覆盖工具测量不同结果的原因。
幸运的是,从 C++17 开始,就不会再有惊喜了,因为动态异常规范已被弃用并从标准中删除,而 throw()
规范仍然有效,但它与 noexcept(true)
.
关于c++ - GCC/GCOV 为使用 throw()/noexcept 的函数生成的不同分支覆盖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43278010/
我使用 gcc -fprofile-arcs -ftest-coverage [filenames] 在一些 .c 文件上运行 gcov 工具。命令 但向该命令提供文件名是一项非常繁琐的工作。 相反,
我可以在 Windows 中安装 gcov 工具吗? 或者我可以在windows的eclipse中使用这个工具的插件吗? 我对这个工具很陌生。我对这个工具没有任何想法。请帮我获取这个工具的信息。 请告
我在 RHEL 上运行 gcov/gcc 4.1.2。 当我想为 gcov 文件指定一个目录时。关于如何执行此操作的任何想法? 最佳答案 从要创建其文件的目录运行 gcov。您必须使用 -o 参数来告
我正在尝试使用 gcov-tool 为多个源文件合并一些现有的覆盖率数据(不是我自己创建的)。但是当我调用 gcov-tool merge dir1 dir2 时,dir1 和 dir2 是包含 .g
我正在运行 gcov 来测量覆盖率,但对于我在 C 代码中使用的每个函数,我都收到“有来自退出 block 的弧”消息。这条消息有什么问题吗?我应该忽略它们吗? 最佳答案 这可能意味着您的 gcno
我正在尝试使用 gcc 4.8.2 和 lcov 1.10 获取 html 覆盖率以进行测试。我确定我的源文件、对象和 gcov 文件位于同一位置,并且我正在从我运行编译器的目录中运行 lcov。 我
我在远程服务器上用 gcov 标志编译了我的源文件。 CFLAGS += -fprofile-arcs -ftest-coverage -lgcov -coverage 编译工作正常。 gcc 4.7
在使用 gcov 支持编译我的项目时,我面临以下错误 以下是我在编译时的标志信息 编译器标志: CXXFLAGS="-Wno-deprecated -g -ggdb -fprofile-arcs -f
我正在尝试在 iPhone 项目上使用 gcov 并遵循 Apple 的说明 here ,但它不起作用。 当我构建并配置项目时,会为每个目标文件创建 .gcda 文件。但没有执行的行记录到 .gcda
我尝试使用 gcov 编译一个简单的应用程序并收到以下链接错误: gcc AllTests.o CuTestTest.o CuTest.o -o TestTest AllTests.o: In fun
资料夹结构 〜/沙盒/ dev 〜/沙盒/测试 我在dev目录中有main.cpp。我使用--coverage标志编译了代码以生成代码覆盖率。 现在,将生成a.out和main.gcno文件。 现在我
我正在使用 gcov 来获取我们项目的代码覆盖率,但它经常报告 50% 的普通函数调用的条件覆盖率。函数是否接受任何参数或返回任何数据都没有任何区别。我在 Jenkins 中使用 gcovr 和 Co
无法使用我的 C/C++ Makefile 项目在 Windows 上使用 mingw32 的 googletest 获取 gcov 覆盖文件完整源代码位于https://github.com/rus
我正在使用 gcov这是我第一次遇到与此 thread 中报告的问题类似的问题.但是,根据该线程中的评论,我无法解决我的问题。 我正在尝试测量 KMyMoney-4.6.4 中具体测试用例的覆盖率,即
我正在使用 eclipse indigo 和 linux 工具。其中一个工具是 gcov 的插件。我有一个项目是 statis lib(点一个文件)和另一个项目是一个单元测试,它与这个 lib 链接并
我在 32 位机器上使用 -fprofile-arcs -ftest-coverage 标志交叉编译我的可执行文件以覆盖。我在 64 位目标机器上运行生成的可执行文件。 当我运行可执行文件时,它不会生
是否可以使用 gcov 进行多线程应用程序的覆盖测试? 我已经对我们的代码库进行了一些简单的测试,但如果能对我们正在实现的覆盖范围有一些了解就更好了。如果 gcov 不合适,任何人都可以推荐一个替代工
我正在使用 gcov 来衡量我贡献的 c++ 库的测试覆盖率。出于某种原因,gcov 无法将许多文件中的行识别为可执行文件。在给定文件的 160 多行中,它会说其中 40 行是可执行的。例如:
MWE #include struct Foo { Foo() { std::cout << "Constructing Foo " << this << std::endl; }
我正在使用 gcov 测量我的 C++ 代码中的覆盖率。我希望能够标记某些源代码行,以便在使用 gcovr 时将它们排除在覆盖率报告之外。我知道它们存在,因为我曾经偶然发现过它们,但现在我找不到看到它
我是一名优秀的程序员,十分优秀!