c/c++语言开发共享告诉gcc函数调用不会返回

我在GCC下使用C99

我有一个函数在头文件中声明为static inline ,我无法修改。

函数永远不会返回,但未标记为__attribute__((noreturn))

如何以告诉编译器不会返回的方式调用该函数?

我从我自己的noreturn函数调用它,部分想要抑制“noreturn函数返回”警告但也想帮助优化器等。

我已尝试在属性中包含声明,但会收到有关重复声明的警告。

我已经尝试创建一个函数指针并将该属性应用于该函数,但它表示函数属性不能应用于指向函数。

    定义的函数和调用外部函数的函数中,添加对__builtin_unreachable的调用,该调用至少包含在GCC和Clang编译器中,并标记为noreturn 。 实际上,这个函数什么都不做,不应该被调用。 它只在这里,以便编译器可以推断程序执行将在此时停止。

     static inline external_function() // lacks the noreturn attribute { /* does not return */ } void your_function() __attribute__((noreturn)) { external_function(); // the compiler thinks execution may continue ... __builtin_unreachable(); // ... and now it knows it won't go beyond here } 

    编辑:只是为了澄清评论中提出的几点,并且通常给出一些背景信息:

    一旦编译器(通过自身或程序员的帮助)建立了一些代码无法访问,它可以使用此信息进行如下优化:

    插图: – 无法删除对external_function的调用,因为它可能有副作用。 事实上,它可能至少具有终止该过程的副作用! – 可以移除your_function的返回锅炉板

    这是另一个示例,显示了如何删除无法访问点之前的代码

     int compute(int) __attribute((pure)) { return /* expensive compute */ } if(condition) { int x = compute(input); // (1) no side effect => keep if x is used // (8) x is not used => remove printf("hello "); // (2) reachable + side effect => keep your_function(); // (3) reachable + side effect => keep // (4) unreachable beyond this point printf("word!n"); // (5) unreachable => remove printf("%dn", x); // (6) unreachable => remove // (7) mark 'x' as unused } else { // follows unreachable code, but can jump here // from reachable code, so this is reachable do_stuff(); // keep } 

    几种解决方案

    使用__attribute__重新声明您的函数

    您应该尝试通过向其添加__attribute__((noreturn))来修改其标头中的该函数。

    您可以使用new属性重新声明某些函数,因为这个愚蠢的测试演示了(向fopen添加属性):

      #include  extern FILE *fopen (const char *__restrict __filename, const char *__restrict __modes) __attribute__ ((warning ("fopen is used"))); void show_map_without_care (void) { FILE *f = fopen ("/proc/self/maps", "r"); do { char lin[64]; fgets (lin, sizeof (lin), f); fputs (lin, stdout); } while (!feof (f)); fclose (f); } 

    用宏覆盖

    最后,您可以定义一个宏

     #define func(A) {func(A); __builtin_unreachable();} 

    (这使用了一个事实,即在宏内部,宏名称不是宏扩展的)。

    如果你的永不返回的func声明为返回例如int你将使用类似的语句表达式

     #define func(A) ({func(A); __builtin_unreachable(); (int)0; }) 

    像上面这样的基于宏的解决方案并不总是有效,例如,如果func作为函数指针传递,或者仅仅是某些人员代码(func)(1)是合法但丑陋的。


    使用noreturn属性重新声明静态内联

    以下示例:

      // file ex.c // declare exit without any standard header void exit (int); // define myexit as a static inline static inline void myexit (int c) { exit (c); } // redeclare it as notreturn static inline void myexit (int c) __attribute__ ((noreturn)); int foo (int *p) { if (!p) myexit (1); if (p) return *p + 2; return 0; } 

    当使用GCC 4.9(来自Debian / Sid / x86-64) gcc -S -fverbose-asm -O2 ex.cgcc -S -fverbose-asm -O2 ex.c )时,会给出一个包含预期优化的汇编文件:

      .type foo, @function foo: .LFB1: .cfi_startproc testq %rdi, %rdi # p je .L5 #, movl (%rdi), %eax # *p_2(D), *p_2(D) addl $2, %eax #, D.1768 ret .L5: pushq %rax # .cfi_def_cfa_offset 16 movb $1, %dil #, call exit # .cfi_endproc .LFE1: .size foo, .-foo 

    您可以使用#pragma GCC诊断来有选择地禁用警告。


    使用MELT定制GCC

    最后,您可以使用MELT插件自定义最近的gcc并编写简单的扩展名(使用MELT域特定语言),以便在包含所需function时添加属性noreturn 。 可能有十几条MELT行,使用register_finish_decl_first和函数名称匹配。

    由于我是MELT (免费软件GPLv3 +)的主要作者,如果您提出要求,我甚至可以为您编写代码,例如此处或最好是在gcc-melt@googlegroups.com ; 给出你永不归来的function的具体名称。

    可能MELT代码看起来像:

      ;;file your_melt_mode.melt (module_is_gpl_compatible "GPLv3+") (defun my_finish_decl (decl) (let ( (tdecl (unbox :tree decl)) ) (match tdecl (?(tree_function_decl_named ?(tree_identifier ?(cstring_same "your_function_name"))) ;;; code to add the noreturn attribute ;;; .... )))) (register_finish_decl_first my_finish_decl) 

    真正的MELT代码稍微复杂一些。 你想在那里定义your_adding_attr_mode 向我询问更多。

    根据需要编写MELT扩展名your_melt_mode.melt (并在MELT教程中记录 ,将MELT扩展编译为your_melt_mode.quicklybuilt.so ),您将编译代码

      gcc -fplugin=melt  -fplugin-arg-melt-extra=your_melt_mode.quicklybuilt  -fplugin-arg-melt-mode=your_adding_attr_mode  -O2 -I/your/include -c yourfile.c 

    换句话说,您只需在MakefileCFLAGS中添加一些-fplugin-*标志!

    顺便说一句,我只是在MELT监视器中进行编码(在github上: https : //github.com/bstarynk/melt-monitor …,文件meltmom-process.melt非常相似。

    使用MELT扩展,您将不会收到任何其他警告,因为MELT扩展将动态改变声明函数的内部GCC AST(GCC )!

    使用MELT定制GCC可能是最具防弹性的解决方案,因为它正在修改GCC内部AST。 当然,它可能是最昂贵的解决方案(并且它是GCC特定的,并且可能需要 – 当GCC正在发展时变小,例如当使用下一版本的GCC时),但是因为我试图certificate它很容易你的情况。

    需要了解更多c/c++开发分享告诉gcc函数调用不会返回,也可以关注C/ C++技术分享栏目—计算机技术网(www.ctvol.com)

      以上就是c/c++开发分享告诉gcc函数调用不会返回相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注(计算机技术网)。

      本文来自网络收集,不代表计算机技术网立场,如涉及侵权请点击右边联系管理员删除。

      如若转载,请注明出处:https://www.ctvol.com/c-cdevelopment/978943.html

      (0)
      上一篇 2021年12月12日
      下一篇 2021年12月12日

      精彩推荐