跳转至

开源代码编码常用技巧

1 do{...}while (0) 的意义和用法

  • 参考资料 在 C++ 中,do { ... } while (0) 是一种常见的编程技巧,通常用于宏定义中。它的主要目的是确保宏的行为类似于一个完整的语句块,从而避免一些潜在的错误和问题。以下是一些使用 do { ... } while (0) 的常见场景和原因:

1.1 避免悬空 else 问题

在宏定义中,如果不使用 do { ... } while (0),可能会导致悬空 else 问题。例如:

#define FOO(x) if (x) a = b; else c = d;

如果在使用这个宏时,代码如下:

if (condition)
    FOO(true);
else
    e = f;

展开后会变成:

if (condition)
    if (true) a = b; else c = d;
else
    e = f;

这会导致 else 与内部的 if 匹配,而不是外部的 if,从而导致逻辑错误。使用 do { ... } while (0) 可以避免这个问题:

#define FOO(x) do { if (x) a = b; else c = d; } while (0)

展开后变成:

if (condition)
    do { if (true) a = b; else c = d; } while (0);
else
    e = f;

这样 else 就会正确地与外部的 if 匹配。

1.2 确保宏的行为类似于语句块

do { ... } while (0) 确保宏的行为类似于一个完整的语句块,可以在宏内部定义局部变量、使用 breakcontinue 等控制流语句。例如:

#define SAFE_DELETE(ptr) do { \
    if (ptr) { \
        delete ptr; \
        ptr = nullptr; \
    } \
} while (0)

这样在使用宏时,可以确保 ptr 被正确删除并置为 nullptr

SAFE_DELETE(myPtr);

1.3 避免多语句宏的副作用

如果不使用 do { ... } while (0),宏展开后可能会导致意外的副作用。例如:

#define SWAP(a, b) { int temp = a; a = b; b = temp; }

如果在使用这个宏时,代码如下:

if (condition)
    SWAP(x, y);
else
    z = w;

展开后会变成:

if (condition)
    { int temp = x; x = y; y = temp; };
else
    z = w;

这会导致语法错误,因为 ; 后面不能直接跟 else。使用 do { ... } while (0) 可以避免这个问题:

#define SWAP(a, b) do { int temp = a; a = b; b = temp; } while (0)

展开后变成:

if (condition)
    do { int temp = x; x = y; y = temp; } while (0);
else
    z = w;

2 (void) val 的意义和用法

  • 功能:在不使用函数的参数时,使用 void 修饰参数可以使编译器不警告
  • 示例
int fun(int a)
{
   (void)a;
   return 0;
}

3 include 实现文件

  • 作用:通常用于既可以将实现与声明分开(动态库场景),又可以实现和声明在同一个头文件(便于使用者直接包含头文件,而不需要链接动态库)。

    以 asio 中类 endpoint 实现代码来讲解

  • endpoint.hpp 文件
class endpoint
{
... 省略
  ASIO_DECL endpoint(int family,
      unsigned short port_num) ASIO_NOEXCEPT;
... 省略
}

#if defined(ASIO_HEADER_ONLY)
# include "asio/ip/detail/impl/endpoint.ipp"
#endif // defined(ASIO_HEADER_ONLY)
  • endpoint.ipp
endpoint::endpoint(int family, unsigned short port_num) ASIO_NOEXCEPT
  : data_()
{
... 省略
}
  • ASIO_HEADER_ONLY 定义如下
// Default to a header-only implementation. The user must specifically request
// separate compilation by defining either ASIO_SEPARATE_COMPILATION or
// ASIO_DYN_LINK (as a DLL/shared library implies separate compilation).
#if !defined(ASIO_HEADER_ONLY)
# if !defined(ASIO_SEPARATE_COMPILATION)
#  if !defined(ASIO_DYN_LINK)
#   define ASIO_HEADER_ONLY 1
#  endif // !defined(ASIO_DYN_LINK)
# endif // !defined(ASIO_SEPARATE_COMPILATION)
#endif // !defined(ASIO_HEADER_ONLY)