Удаление нулевых предупреждений в Splint

Я пробовал Splint с недавно написанной программой на языке C и пытался понять и удалить предупреждения, которые она выдает. . Один я понимаю, но не могу понять, как его удалить из следующего фрагмента кода:

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; 
}

Сплинту не нравится, что функция может возвращать NULL, но в данном случае это имеет смысл.

Я пытался использовать /@nullwhenfalse@/, но, кажется, это работает только в том случае, если функция возвращает true/false, а также пытался изменить код для использования retVal и пробовал оба /@null@< /em>/ и /@relnull@/ перед объявлением, но они ничего не сделали.

(Кроме того, размер таблицы составляет всего 20 больших атм, поэтому нет смысла использовать умный алгоритм поиска.)


person Makis    schedule 19.11.2009    source источник
comment
Я думаю, вам следует а) не объявлять аргумент передачи по значению как const, но, возможно, это ваш стиль, и б) включать фактический диагностический вывод, который дает вам Splint, not happy немного расплывчато.   -  person unwind    schedule 19.11.2009
comment
Хм, почему бы мне не объявить его константным? Мне нравится константа отчасти потому, что она дает понять, что значение не будет изменено функцией.   -  person Makis    schedule 19.11.2009
comment
ЛАДНО ЛАДНО. Я действительно понял, почему вам не нравится использовать const, когда я нажал кнопку отправки. Хороший момент, я просто автоматически добавляю const ко всем входным параметрам, не учитывая, передается ли это по значению или по ссылке.   -  person Makis    schedule 19.11.2009
comment
@unwind Аргумент const int id помогает компилятору предупредить вас, если вы случайно измените id, что вы можете счесть желательным (хотя я бы не стал его использовать).   -  person Pascal Cuoq    schedule 19.11.2009
comment
@Makis Дело в том, что вы не добавляете его на тот же уровень, если вы добавляете его, не учитывая, передается ли он по значению или по ссылке. Я считаю, что экспериментировал с C, и я делаю паузу, чтобы подумать каждый раз, когда использую квалификатор типа. Я бы не рекомендовал использовать их автоматически.   -  person Pascal Cuoq    schedule 19.11.2009


Ответы (3)


Вы должны дважды проверить использование /*@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;
}

Если у вас все еще есть подобное предупреждение, может ли оно быть связано с другой частью вашего кода?

person Jerome    schedule 19.11.2009

splint -nullret уничтожит это предупреждение (глобально), которое может быть или не быть тем, что вы хотите сделать. В некоторых случаях, если вы не уверены, что тип return NULL верен, вам, вероятно, нужно предупреждение.

Я протестировал пример Джерома, и он заглушил предупреждение для этой конкретной функции.

person Tim Post♦    schedule 19.11.2009
comment
Да, это убрало бы предупреждение, но я не хочу избавляться от него полностью. - person Makis; 19.11.2009
comment
@Makis: Да, в таком случае лучше сделать то, что предлагает Джером, на самом деле я проголосовал за его ответ. - person Tim Post♦; 19.11.2009

Что бы вы ни делали, я бы настоятельно рекомендовал не встраивать сплинт-коды непосредственно в исходный код, а вместо этого обернуть эту функциональность в макрос.

Например, в проекте 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(), мы меняем его в одном месте. Мы также можем поддерживать несколько нотаций для нескольких инструментов или компиляторов.

person Andy Lester    schedule 31.03.2010