【问题标题】:Lint: Call to function 'memcpy(void *, const void *, std::size_t)' violates semantic '(3n>4)'Lint:调用函数 'memcpy(void *, const void *, std::size_t)' 违反语义 '(3n>4)'
【发布时间】:2014-03-08 23:59:22
【问题描述】:

这是我的代码库的一部分。 我没有得到警告的含义,因此无法解决此问题... 代码:

struct ParamsTube{
    uint8                Colours01[4];
    uint8                Colours02[4];
    uint8                Colours03[4];
};

void sample_fun(const uint8 *diagData){
    ParamsTube Record;
    memcpy(&Record.Colours01[0], &diagData[0], 4); //Line 1
    memcpy(&Record.Colours02[0], &diagData[4], 4); //Line 2
    memcpy(&Record.Colours03[0], &diagData[8], 4); //Line 3
}

第 1,2 和第 3 行此逻辑的 LINT 警告 426 是

Call to function 'memcpy(void *, const void *, std::size_t)' violates semantic '(3n>4)'

你能告诉我这到底是什么意思吗.....

【问题讨论】:

  • 您将相同的值复制到所有颜色变量中。源始终是&diagData[0]。您的意思是&diagData[0]&diagData[4]&diagData[8]
  • 对不起 ..我已经正确修改了 ..它的应对 frm diagdata[0],1 和 2 ...这是在上面修改的..现在对于这个代码库我收到了警告..
  • @MariusBancila,索引应该是 4 的倍数吗????
  • 作为旁注,我会使用 sizeof(uint8)。
  • 我认为这是来自 lint 而不是编译器的消息是否正确?

标签: c++ lint


【解决方案1】:

(3n > 4) 表示用于调用memcpy() 的第三个参数应大于4,并且您的调用违反了此语义。语义似乎表明memcpy() 不应用于复制小于机器字(通常为 4)的数据。这就是 lint 警告您的原因。语义是否合适是另一个问题。


下面是lint warning 426的解释:

426 对函数“符号”的调用违反语义“字符串”- 当违反用户语义(由 -sem 定义)时发出此警告消息。 “字符串”是被违反的语义的子部分。例如:

//lint -sem( f, 1n > 10 && 2n > 10 )  
        void f( int, int );  
        ...  
        f( 2, 20 );  

消息中的结果:

Call to function 'f(int, int)' violates semantic '(1n>10)'

因此,您环境中的 memcpy() 可能具有如下领先的 lint 语义:

// lint -sem(memcpy, 3n > 4)
void* memcpy(void* s1, const void* s2, std::size_t n);

对于您的情况,如果您想要实现的实际上是:

memcpy(&Record.Colours01[0], &diagData[0], 4); //Line 1
memcpy(&Record.Colours02[1], &diagData[4], 4); //Line 2
memcpy(&Record.Colours03[2], &diagData[8], 4); //Line 3

然后简单地说:

memcpy(&Record, diagData, sizeof(Record));  

将在不触发 lint 警告的情况下完成所有工作。

【讨论】:

  • 如提到的memcpy函数第三个参数是4..所以它等于4和条件(3n>4)..怎么不满足?
  • @Ashwin:第三个参数4等于4,但不大于4,所以不满足(3n > 4)的要求。 3n 指定第三个参数。
  • 根据我的算法..它应该是 4 ..不超过 4 ..那么我应该如何解决这个警告??
  • +1... 比我的更快更完整。我只是添加了this reference,它声明它可以在编译时使用类似 memcpy 的内在函数执行一些检查。
  • 复制 4 个字节我会使用 "="... *(uint4 *)&dest = *(uint4 *)&source;
【解决方案2】:

Lint 告诉您,您不应为 4 个或更少的字节调用 memcpy

这太愚蠢了。

现代编译器知道memcpy 是什么。如果您在 GCC 或 Clang 上使用优化进行编译,至少,您会发现在 x86 上,在生成的代码中,4 字节 memcpy 已被单个 mov 替换。 (嗯,从内存复制到内存时可能有两个movs。)

您编写此代码的方式是唯一可移植、安全的编写方式,无需逐个写入字节副本。特别是,编写这段代码是不可移植的:

*((uint32_t*)&Record.Colours01[0]) = *((uint32_t*)&diagData[0]);

这适用于 x86,但只是因为该平台允许未对齐的访问。但是如果diagData[0] 没有与 4 字节边界对齐(并且绝对没有理由假设它会对齐),那就是未对齐的访问,并且很可能在其他平台上触发陷阱(ARM 具有对齐检查模式; IA-64 和后期的 Alpha 根本不支持非对齐访问,各种嵌入式芯片也是如此)。

就此而言,您甚至不能假设Colours01 是对齐的。编译器应该对齐它确实没有任何约束力。堆栈上的其他变量很可能会使其不对齐。

无论对齐方式如何,memcpy 都是安全的,同时让编译器有机会将其优化为它认为最有效的任何方式(例如 x86 上的mov,其中未对齐的访问是安全的,并且可能更快比替代品)。

对于 Lint 的作者或 memcpy 上的注解,Lint 抱怨这是一个严重的错误。无论哪种方式,您都不应该遵循此规则;它会导致更糟糕的代码。

【讨论】:

    猜你喜欢
    • 2012-03-09
    • 2014-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-28
    相关资源
    最近更新 更多