【问题标题】:Serial- / Socket IO and GCC nothrow attributeSerial-/Socket IO 和 GCC nothrow 属性
【发布时间】:2012-12-03 19:51:08
【问题描述】:

我有用 C 实现抽象 serial-socket IO (Linux / Windows) 的函数。 它们都被标记为extern "C",因为它们也可能被 C++ 调用。

在这里使用__attribute__((__nothrow__))(或MinGW Macro __MINGW_NOTHROW)是否安全/我可以假设没有抛出异常吗?

调用函数 - 套接字:
(未列出 WinSock 的所有新增功能)

  • socket
  • connect
  • send / recv
  • close(Windows 上为closesocket
  • sendto / recvfrom

调用函数 - 串行:
由于 windows / linux 之间的串行 IO 代码差异很大,此处并未列出所有函数

  • Linux (GNU)
    • open
    • tcgetattr
    • read / write
    • close
  • Windows (MinGW)
    • CreateFile
    • GetCommState / SetCommTimeouts
    • ReadFile / WriteFile
    • CloseHandle

由于 ANSI C 没有异常(如果我错了请纠正我)它们不会被抛出,但是 GCC 扩展和 OS API 调用呢?

文档:http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html(参见nothrow)。

【问题讨论】:

  • 如果您使用 C(而不是 C++)编写代码,为什么还要为异常烦恼?无论如何,您对它们无能为力。
  • 这将允许 GCC 进行一些优化。但是,如果从 C++ 调用,我不想造成麻烦。

标签: c gcc io mingw


【解决方案1】:

C

GNU C (Linux) 使用 __THROW 宏而不是 __MINGW_NOTHROW。 虽然 MinGW 仅是 __nothrow__ 属性,但 __THROW 也包含 __leaf__ 属性。

C++

如果你使用 C++,__THROW 有另一个含义:throw()——表示不抛出异常(类似于__nothrow__;但在 C++ 标准中定义)。

所以这取决于您是使用 C 还是 C++编译,而不是取决于您调用函数的来源(仅限 GNU C / C++!)。

示例:

void f() __THROW;

被视为...

GNU C:

void f() __attribute__((__nothrow__, __leaf__))

GNU C++:

void f() throw()

函数1)取消点,因此没有标记 __THROW:

  • open()
  • read()
  • write()
  • close()
  • connect()
  • send()
  • recv()
  • close()
  • sendto()
  • recvfrom()

函数1)标记__THROW

  • tcgetattr()
  • socket()

至少,这些都保存到__nothrow__

相比之下,MinGW 没有区别 C 与 C++;在这两种情况下都设置了属性。

使用上面的示例,__nothrow__ 设置在 C C++:

void f() __attribute((__nothrow__))

函数1)未标记__MINGW_NOTHROW

  • socket()
  • connect()
  • send()
  • recv()
  • closesocket()
  • sendto()
  • recvfrom()
  • CreateFile()
  • GetCommState()
  • SetCommTimeouts()
  • ReadFile()
  • WriteFile()
  • CloseHandle()

简而言之:无!

兼容性

与 C

期望与 C++ 互操作的 C 语言代码应该是 使用 -fexceptions 编译。这将使调试成为 C 语言 作为 C++ 引起的堆栈展开的一部分调用的函数是可能的。

特别是展开到没有异常处理数据的帧 将导致运行时中止。如果放卷机用完放卷信息 在找到处理程序之前,调用 std::terminate() 。

请注意,大多数开发环境都应注意 正确处理这些细节。对于 GNU 系统,所有适当的部分 GNU C 库已经用 -fexceptions 编译。

(来源:http://gcc.gnu.org/onlinedocs/libstdc++/manual/using_exceptions.html

因此使用-fexceptions 进行编译,不需要等效属性。如果您只能标记特定功能,则必须/应该使用__nothrow__

但是虽然使用__nothrow__ 属性看起来只在 GNU C++ 上保存,而在 Linux 上使用 GNU C 的一些功能,在 Windows 上就不是那么清楚了。


附录:

为了避免这个问题的某些部分,我编写了一个类似于__THROW 但也可以在 MinGW 上使用的宏:

#if defined __GNUC__
    #ifndef __THROW
        #ifdef  __cplusplus
            #define __THROW         throw()
        #else
            #define __THROW         __attribute__((__nothrow__))
        #endif
    #endif
#else
    #define __THROW
#endif

注意: __leaf__ 不包括在内。


1)只谈论我的问题中列出的那些。

【讨论】:

    【解决方案2】:

    注意 gcc 版本,nothrow 已在 gcc 3.3 中引入!

    你可以将__THROWsys/cdefs.h移植到mingw:

    /* skip this entire part on linux (= glibc available)*/
    #if defined __GNUC__ && !defined __linux__
    
    /********* port __GNUC_PREREQ macro to mingw *********/
    # if !defined __GNUC_PREREQ
    
    # if !defined __MINGW_H
    #  include <_mingw.h>
    #  define __GNUC_PREREQ(major, minor)       __MINGW_GNUC_PREREQ(major, minor)
    # else
    #  if defined (__GNUC_MINOR__)
    #   define __GNUC_PREREQ(major, minor)      __GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
    #  else
    #   define __GNUC_PREREQ(major, minor)      0
    #  endif
    # endif 
    
    #endif /* __GNUC_PREREQ */
    
    
    /********* from gnu c blirary *********/
    
    /* All functions, except those with callbacks or those that
       synchronize memory, are leaf functions.  */
    # if __GNUC_PREREQ (4, 6) && !defined _LIBC
    #  define __LEAF , __leaf__
    #  define __LEAF_ATTR __attribute__ ((__leaf__))
    # else
    #  define __LEAF
    #  define __LEAF_ATTR
    # endif
    
    /* GCC can always grok prototypes.  For C++ programs we add throw()
       to help it optimize the function calls.  But this works only with
       gcc 2.8.x and egcs.  For gcc 3.2 and up we even mark C functions
       as non-throwing using a function attribute since programs can use
       the -fexceptions options for C code as well.  */
    # if !defined __cplusplus && __GNUC_PREREQ (3, 3)
    #  define __THROW       __attribute__ ((__nothrow__ __LEAF))
    #  define __THROWNL     __attribute__ ((__nothrow__))
    #  define __NTH(fct)    __attribute__ ((__nothrow__ __LEAF)) fct
    # else
    #  if defined __cplusplus && __GNUC_PREREQ (2,8)
    #   define __THROW      throw ()
    #   define __THROWNL    throw ()
    #   define __NTH(fct)   __LEAF_ATTR fct throw ()
    #  else
    #   define __THROW
    #   define __THROWNL
    #   define __NTH(fct)   fct
    #  endif
    # endif
    
    #else   /* Not GCC.  */
    
    # define __inline       /* No inline functions.  */
    
    # define __THROW
    # define __THROWNL
    # define __NTH(fct) fct
    
    #endif  /* GCC.  */
    

    完整代码见glibc - sys/cdefs.h

    edit:__GNUC_PREREQ可以替换成__MINGW_GNUC_PREREQ(major, minor),那么就不用像上面那样重新定义了。

    【讨论】:

      猜你喜欢
      • 2019-05-30
      • 1970-01-01
      • 1970-01-01
      • 2017-05-03
      • 1970-01-01
      • 1970-01-01
      • 2018-04-21
      • 2018-06-24
      • 2014-10-18
      相关资源
      最近更新 更多