1

我有在 C 中实现的抽象串行套接字 IO(Linux / Windows)的函数。它们都被标记为,extern "C"因为它们也可以从 C++ 中调用。

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

调用函数 - 套接字:(
未列出 WinSock 的所有添加项)

  • socket
  • connect
  • send/recv
  • closeclosesocket在 Windows 上)
  • sendto/recvfrom

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

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

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

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

4

2 回答 2

5

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__在 CC++ 上设置:

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) 只谈论我的问题中列出的那些。

于 2013-03-02T20:52:47.953 回答
1

照顾 gcc 版本,nothrow已与 gcc 3.3 一起引入!

你可以__THROWsys/cdefs.hmingw 移植:

/* 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

编辑: __GNUC_PREREQ可以替换为__MINGW_GNUC_PREREQ(major, minor),那么您不必像上面那样重新定义它。

于 2013-03-02T23:16:54.943 回答