编译关于非普通旧数据的memset的时间警告

时间:2013-07-30 11:58:54

标签: c++ compiler-warnings

我正在开发一个大型代码库,将一些旧的C模块转换为C ++。我想在结构中添加一个C ++对象,但是这个结构的一些用户memset,这对于我想放在结构中的对象是不幸的。

如何在编译时检测到这是否已完成,以便我可以在不再是POD的结构上消除memset的所有使用?

4 个答案:

答案 0 :(得分:8)

我不确定编译器是否会通过直接提供一些编译标志来帮助你。如果确实如此,对你有好处。用那个。故事结束。

如果没有,那么这可能对你有帮助。由于您将代码从C转换为C ++,这意味着memset的所有用法都没有std::命名空间。因此,请利用这一事实,#define memset为:

 #define memset memset_if_pod_else_error() 

这里memset_if_pod_else_error是您编写的函数(即您必须实现它)。您可以将其设为模板,以便推断出参数的类型,然后检测该类型是否为POD。如果是POD,则可以在内部调用std::memset,否则会引发错误。

std::enable_ifstd::is_pod等元功能将帮助您实现此功能。

以下是这个想法的最小演示:

#include <iostream>
#include <type_traits>
#include <cstring>

auto ptr_memset =  std::memset; //store this a pointer

template<typename T>
using VoidPtr = typename std::enable_if<std::is_pod<T>::value, void*>::type;

#define memset memset_if_pod_else_error

template<typename T>
VoidPtr<T> memset_if_pod_else_error(T *data, int ch, size_t count) 
{
      return ptr_memset(data, ch, count);
}

struct pod {};
struct nonpod { nonpod() {} };

int main()
{
    pod p;
    nonpod np;

    memset(&p, 0, sizeof(p));

    memset(&np, 0, sizeof(np));  //this is error!
}

第二次调用memset会产生此错误:

  

错误:没有匹配函数来调用'memset_if_pod_else_error'
          memset(&amp; np,0,sizeof(np));
         ^ ~~~~~

Online Demo

希望有所帮助。

答案 1 :(得分:2)

这个怎么样:

auto orig_memset =  std::memset;
#define memset checked_memset

template <class T>
void* checked_memset(T* ptr, int value, size_t num) {
  static_assert(std::is_pod<T>::value, "memset on non-POD");
  return original_memset(data, value, num);
}

或者,如果您只对查找特定结构的违规行为感兴趣:

auto original_memset =  std::memset;
#define memset checked_memset

template <class T>
void* checked_memset(T* ptr, int value, size_t num) {
  static_assert(!std::is_same<T, YOUR_STRUCT_HERE>::value, "memset used on YOUR_STRUCT_HERE");
  return original_memset(data, value, num);
}

答案 2 :(得分:1)

我认为您无法在编译时检测到对非POD数据使用memset

您可以做的是添加一些在构造函数中设置的额外字段,然后在任何其他成员函数中进行检查。像这样:

 class X
 {
    const int MAGIC = 123456789;
    int magic;
    ...
  public:
    X() : magic(MAGIC) { ... }
    ... 
    void do_stuff()
    {
       check_magic();
       ... 
    } 
  private: 
    void check_magic() 
    { 
      if (magic != MAGIC) { ... do something to indicate bad state ... }; 
    }
 }; 

显然,这可以“仅在调试版本上”完成。

答案 3 :(得分:0)

在这种情况下,不是试图找到所有问题区域,我建议首先防止它们。具体来说,不要将任何C ++功能添加到现有的C结构中,而是使用包含C数据​​结构实例的适当的interfcace编写类。然后,您将保持与旧结构和代码的完全向后兼容性,以及添加您感兴趣的新C ++功能。