2

我一直在用我最近编写的 C 程序尝试Splint,并试图理解和删除它给出的警告。我理解但不明白如何删除它来自以下代码片段:

static MyType_t *findById(const int id)
{
    int i;

    for (i = 0; i < MY_ARR_SIZE; i++) {
            if (my_arr[i].id == NOT_SET) {
                    /* Items are sorted so that items with 
                    NOT_SET as ID are at the end of the array */
                    break;
            }
            if (my_arr[i].id == id) {
                    return &(my_arr[i]);
            }
    }
    return NULL; 
}

Splint 对函数可以返回 NULL 感到不高兴,但在这种情况下,它非常有意义。

我尝试使用 / @nullwhenfalse@ / 但它似乎只有在函数返回 true/false 并且还尝试更改代码以使用 retVal 并尝试 / @null@ / 和 / @relnull@ / 的情况下才有效声明,但这些什么也没做。

(顺便说一句,这张桌子只有 20 个大 atm,所以没有必要使用聪明的搜索算法。)

4

3 回答 3

6

您应该在声明前仔细检查 /*@null@*/ 的使用。

在您的示例的以下可编译版本中,它确实删除了警告(使用夹板 3.1.2):

typedef struct { int id; } MyType_t;
#define NOT_SET -1
#define MY_ARR_SIZE 20
static MyType_t my_arr[MY_ARR_SIZE];

/*@null@*/ static MyType_t *findById(const int id)
{
    int i;
    for (i = 0; i < MY_ARR_SIZE; i++) {
            if (my_arr[i].id == NOT_SET) {
                    /* Items are sorted so that items with 
                    NOT_SET as ID are at the end of the array */
                    break;
            }
            if (my_arr[i].id == id) {
                    return &(my_arr[i]);
            }
    }
    return NULL;
}

int main() {
    (void)findById(10);
    return 0;
}

如果您仍然有类似的警告,可能是关于您的代码的另一部分吗?

于 2009-11-19T11:24:21.910 回答
1

splint -nullret将(全局)压制该警告,这可能是您想要做的,也可能不是。在某些情况下,除非您确定返回 NULL 的类型是正确的,否则您可能需要警告。

我测试了 Jerome 的示例,它确实消除了对该特定功能的警告。

于 2009-11-19T11:28:23.653 回答
1

无论你做什么,我强烈建议不要将夹板代码直接嵌入到源代码中,而是将该功能包装在一个宏中。

例如,在 Parrot 项目中,我有这些宏

#  define ARGIN(x)                    /*@in@*/ /*@notnull@*/
#  define ARGIN_NULLOK(x)             /*@in@*/ /*@null@*/
    /* The pointer target must be completely defined before being passed */
    /* to the function. */

#  define ARGOUT(x)                   /*@out@*/ /*@notnull@*/
#  define ARGOUT_NULLOK(x)            /*@out@*/ /*@null@*/
    /* The pointer target will be defined by the function */

然后使用宏,所以我们可以使用:

void copy_string( ARGOUT(char *target), ARGIN(const char *source ) ) ...

如果我们想更改 ARGIN() 参数的处理方式,我们将其更改为一处。我们还可以支持多种工具或编译器的多种表示法。

于 2010-03-31T21:47:34.280 回答