使用 memset 清除非平凡类型的对象时出错

Posted

技术标签:

【中文标题】使用 memset 清除非平凡类型的对象时出错【英文标题】:error clearing an object of non-trivial type with memset 【发布时间】:2021-02-25 12:00:13 【问题描述】:

嗯,事情很简单,我明白了 warning: ‘void* memset(void*, int, size_t)’ clearing an object of non-trivial type ‘struct FormatHashBuffers(CBlock*, char*, char*, char*)::<unnamed>’; use assignment or value-initialization instead [-Wclass-memaccess] memset(&tmp, 0, sizeof(tmp)); 关于这个函数和 idk 为什么,当我用 g++ 5 构建时没有警告,但是当我用 7.1 或 8.5 构建时我得到警告,知道为什么或如何解决它吗?提前致谢。

    void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata,
                       char* phash1) 
    //
    // Pre-build hash buffers
    //
    struct
    
        struct unnamed2
        
            int nVersion;
            uint256 hashPrevBlock;
            uint256 hashMerkleRoot;
            unsigned int nTime;
            unsigned int nBits;
            unsigned int nNonce;
        
        block;
        unsigned char pchPadding0[64];
        uint256 hash1;
        unsigned char pchPadding1[64];
    
    tmp;
    memset(&tmp, 0, sizeof(tmp));

    tmp.block.nVersion = pblock->nVersion;
    tmp.block.hashPrevBlock = pblock->hashPrevBlock;
    tmp.block.hashMerkleRoot = pblock->hashMerkleRoot;
    tmp.block.nTime = pblock->nTime;
    tmp.block.nBits = pblock->nBits;
    tmp.block.nNonce = pblock->nNonce;

    FormatHashBlocks(&tmp.block, sizeof(tmp.block));
    FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1));

    // Byte swap all the input buffer
    for (unsigned int i = 0; i < sizeof(tmp) / 4; i++)
        ((unsigned int*)&tmp)[i] = ByteReverse(((unsigned int*)&tmp)[i]);

    // Precalc the first half of the first hash, which stays constant
    SHA256Transform(pmidstate, &tmp.block, pSHA256InitState);

    memcpy(pdata, &tmp.block, 128);
    memcpy(phash1, &tmp.hash1, 64);

【问题讨论】:

为什么不在你的类中初始化成员变量呢? 警告是在版本 5 和版本 7.1 之间的某个时间添加的。 (开发人员在特殊情况下添加警告的时间有限。)您可以通过不以未定义行为方式使用 memset 来解决问题。 【参考方案1】:

要初始化结构变量,您可以使用

tmp = ;

【讨论】:

【参考方案2】:

知道为什么

显然,没有为您的 g++ v5 环境正确设置 -Werror 标志,或者当时开发人员没有考虑到它。它应该总是产生这个警告。

如何解决?

这里根本不指memset!由于至少相反,由于存在 SHA256Transform(),因此可以忽略可能的性能问题,因此您应该更喜欢在这里进行干净的显式初始化。尽量避免嵌套结构(因为内部已经在更“全局”的范围内使用过)并参考聚合/统一初始化或显式工厂方式。

【讨论】:

我应该在哪里引用 memset?请帮我解释一下我应该如何解决这个问题,我接受你的回答。 Ted Lyngmo 比我快 :) 看看他的回答。【参考方案3】:

你可以默认初始化你的成员变量:

struct 
    struct unnamed2 
        int nVersion;
        uint256 hashPrevBlock;
        uint256 hashMerkleRoot;
        unsigned int nTime;
        unsigned int nBits;
        unsigned int nNonce;
     block;

    unsigned char pchPadding0[64];
    uint256 hash1;
    unsigned char pchPadding1[64];
 tmp;

这样就不需要memset(&amp;tmp, 0, sizeof(tmp));,警告就会消失。

【讨论】:

我正在编译,如果没有警告,我同意你的回答。谢谢大佬! 好吧,你不能假设memset的使用纯粹是为了初始化。如果您纯粹想重置数据,也可能需要使用 memset - 我会说快速而脏的 memset 仍然有效。 @Tobibobi 我会说我更喜欢memset 而不是为目标分配默认初始化对象的情况很少。如果tmp = decltype(tmp); 生成的代码效率低于memset 并且它总是 对于可以 默认初始化的类型有效,我会感到惊讶。这也是未来的证明。如果将默认初始化更改为其他内容,将0 直接写入内存,memset 将导致难以找到错误,而tmp = decltype(tmp); 仍然会做正确的事情。

以上是关于使用 memset 清除非平凡类型的对象时出错的主要内容,如果未能解决你的问题,请参考以下文章

非平凡的响应式设计布局技术(即四处移动)

如何将 std::variant 与非平凡的用户对象(稍后构建)一起使用,并让访问者使用自动 lambda?

如何使用 memset 清除 char 数组 [重复]

使用 memset 清除基类成员

Python 非平凡的 C++ 扩展

WebService生成XML文档时出错。不应是类型XXXX。使用XmlInclude或SoapInclude属性静态指定非已知的类型。