为什么 PC-Lint 会抱怨重新声明错误 18?

问题描述

请注意,以下代码毫无意义,我只是想重现我在更复杂的代码库中看到的错误。显然,我不会创建一个具有全局作用域的变量来将其传递给仅在该变量所在的一个文件中使用的函数

我正在运行 PC-Lint 9.00L。

在以下示例中,PC-Lint 抱怨重新声明:

example2.c 18 Error 18: Symbol'testFunction(const struct AnotherExample_t *)' redeclared (Arg. no. 1:qualification) 与第 21 行,文件 example.h,模块 example1.c 冲突

代码如下:

example.h

#ifndef EXAMPLE_H
#define EXAMPLE_H

#include <stdint.h>

typedef struct
{
    volatile uint8_t item1;
    volatile uint8_t item2;
} Example_t;

typedef struct
{
    Example_t * p_items;
    uint8_t something;
    uint16_t somethingElse;
} AnotherExample_t;

extern AnotherExample_t g_externalVariable;

extern void testFunction (AnotherExample_t const * const p_example);  //line 21
    
#endif

example1.c

#include "example.h"
#include <stdio.h>

int main(void)
{
    g_externalVariable.something = 5;
    
    (void)printf("%d",g_externalVariable.something);
    
    testFunction(&g_externalVariable);
    return 0;
}

example2.c

#include "example.h"
#include <stdio.h>

static Example_t p = 
{
    .item1 = 0,.item2 = 1,};

AnotherExample_t g_externalVariable =
{
    .p_items = &p,.something = 2,.somethingElse = 3,};

void testFunction (AnotherExample_t const * const p_example)
{  // Line referenced in lint (line 18)
    (void)printf("%d",(int)p_example->somethingElse);
}

为什么 lint 会抛出这个错误

我尝试过的事情

我注意到,当我删除 const AnotherExample_t 的声明时,投诉消失了。即 -

extern void testFunction (AnotherExample_t * const p_example);  //example.h

void testFunction (AnotherExample_t * const p_example)  //example2.c
{
    ...
}

我还尝试从 example1.c 进行调用以查看是否有任何改变:

testFunction((AnotherExample_t const * const)&g_externalVariable);

这并没有改变任何东西。

在这两种情况下,我都会收到一条信息 818 消息:

example2.c 20 Info 818:指针参数“p_example”(第 17 行)可以声明为指向 const

最少的可重复代码

这也会导致同样的错误

example.h

#ifndef EXAMPLE_H
#define EXAMPLE_H

extern void testFunction (const char * const p_example);
    
#endif

example1.c

#include "example.h"
#include <stdio.h>

int main(void)
{
    char testValue = 'c';
    char * p_testValue = &testValue;
    
    testFunction(p_testValue);
    
    return 0;
}

example2.c

#include "example.h"
#include <stdio.h>

void testFunction (const char * const p_example)
{
    (void)printf("%c",p_example);
}

解决方法

这既不是 PC-Lint 的错误,也不是我的代码中的错误。编译器库中的一些关键字重新定义导致 PC-Lint 在其预处理步骤中剥离了一些关键字(例如 constvolatile)。

最终结果是,当我添加 #include <stdio.h> 时,我对 testFunction 的定义将被去除其 const 限定符,并且它将不再与我的标头中的声明匹配。

我在 co-XXXX.lnt 文件中添加了以下选项,错误消失了。

+dconst=const
+dvolatile=volatile

特别感谢 Gimpel 工作人员愿意与我一起解决这个问题,尽管该版本的 PC-Lint 不再受支持。

更新

不幸的是,我没有时间追踪 constvolatile 在库中被重新定义的位置,但我找到了比重新定义更好的解决方法lint 编译器选项文件中的这些关键字。利用 PC-Lint 中的 -scavenge 选项,然后运行该选项通过预处理器创建的 .c 文件会创建一个标头,该标头定义编译器的内置宏以供 PC-Lint 使用。这是我使用的过程。

lint-nt -i"/path/to/my/libraries" -scavenge(*.h) > interim.c

然后,我从 Code Composer Studio 运行了我的代码的标准构建,以验证哪些选项正在使用 cl430 编译器运行。之后,我使用相同的选项通过编译器运行了interim.c - 唯一的例外是我使用-ppo 选项仅通过预处理器运行它,将结果文件保存为intermediate.lnt。

此时,PC-Lint 手册说要运行:lint -scavenge(clean,interim.lnt)。在我的情况下,似乎只清除了所有数据的文件,所以我跳过了这一步。但是,检查在此步骤之前创建的中间 .lnt 文件显示我的所有宏都是在此文件中创建的。我将其重命名为 lint_header.h 并将以下几行添加到我的 co-MSP430.lnt 文件的开头:

-header(lint_header.h)
+libh(lint_header.h)

我不再对 constvolatile 使用 +d 选项,现在可以更准确地表示我的库文件应该如何用于 PC-Lint。我也不再有重新声明错误。