【问题标题】:Removing null warnings in Splint删除 Splint 中的空警告
【发布时间】:2009-11-19 11:01:35
【问题描述】:

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

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,所以没有必要使用聪明的搜索算法。)

【问题讨论】:

  • 我认为你应该 a) 不要将传递值参数声明为“const”,但也许这就是你的风格,并且 b) 包括 Splint 给你的实际诊断输出,“不开心”有点模糊。
  • 嗯,我为什么不把它声明为 const 呢?我喜欢 const 的部分原因是它清楚地表明该值不会被函数更改。
  • 好的,好的。我实际上意识到为什么在我按下提交按钮的那一刻你不喜欢使用 const 。好点,我只是自动将 const 添加到所有输入参数,而不考虑它是按值传递还是按引用传递。
  • @unwind const int id 参数可以帮助编译器在您不小心修改 id 时发出警告,这是您认为可取的(不过我不会使用它)。
  • @Makis 的重点是,如果您在不考虑它是按值传递还是按引用传递的情况下添加它,那么您就不会在同一级别添加它。我认为自己在 C 中进行了实验,每次使用类型限定符时我都会停下来思考。我不建议“自动”使用它们。

标签: c static-analysis syntax-checking splint


【解决方案1】:

你应该仔细检查 /*@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;
}

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 是的,这将删除警告,但我不想完全摆脱它。
    • @Makis:是的,在这种情况下,最好按照杰罗姆的建议去做,事实上我已经对他的回答投了赞成票。
    【解决方案3】:

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

    例如,在 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() 参数的处理方式,我们将其更改为一处。我们还可以支持多种工具或编译器的多种表示法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-18
      • 1970-01-01
      • 1970-01-01
      • 2010-12-31
      • 1970-01-01
      • 2015-05-05
      • 1970-01-01
      • 2019-08-04
      相关资源
      最近更新 更多