C предупреждение Отсутствует страж в вызове функции - PullRequest
41 голосов
/ 09 марта 2010

Это мое предупреждение.

Missing sentinel in function call

Как я могу его удалить.

Я использую компилятор linux & gcc.

Ответы [ 8 ]

62 голосов
/ 09 июля 2010

Похоже, что вы не завершили объявление массива с NULL. Без нуля у вас может быть странность памяти, поскольку среда выполнения не будет знать, где заканчивается массив, и начинается следующий бит памяти.

46 голосов
/ 25 августа 2012

Я только что столкнулся с той же проблемой. Код, который вызывал его для меня, был ...

execl("/bin/bash", "/bin/bash", fname, '\0');

но это должно быть ...

execl("/bin/bash", "/bin/bash", fname, (char *)0);

Проблема с первой версией заключается в том, что список параметров должен заканчиваться нулевым указателем. Но '\ 0' - это не нулевой указатель, это нулевой символ. Таким образом, значение (0) является правильным, это просто неправильный тип.

(char *) 0 также равен нулю, но приводится как char указатель , который является нулевым указателем (т.е. он указывает на адрес 0). Это необходимо для того, чтобы система могла определить, где заканчивается список параметров, чтобы она не продолжала сканировать параметры после последнего. Это приведет к недействительным указателям, которые могут указывать на любую память, что, вероятно, приведет к ошибке сегментации.

То, что (char *) 0 называется часовым, и это то, чего не хватало в первом примере.

Наконец, обратите внимание, что NULL определяется как (void *) 0, поэтому

execl("/bin/bash", "/bin/bash", fname, NULL);

Работает так же хорошо и немного удобнее. (Спасибо @mah за это).

18 голосов
/ 20 сентября 2010

В Xcode, если вы кодируете в target-c и используете некоторые методы, которые принимают список переменных параметров, вам нужно добавить nil объект в конце списка.

Например:

N SArray * names = [NSArray arrayWithObjects: @ "Name1", @ "Name2"]; // приведет к предупреждению, указанному выше

Однако, NSArray * names = [NSArray arrayWithObjects: @ "Name1", @ "Name2", nil]; // Правильно

Надеюсь, это поможет!

11 голосов

Используйте (void*)0 или (void *)NULL вместо NULL

Предупреждение генерируется атрибутом функции sentinel, как указано Jichao . Документально подтверждено по адресу: https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Function-Attributes.html#index-g_t_0040code_007bsentinel_007d-function-attribute-3226, в котором говорится:

Допустимый NULL в этом контексте определяется как ноль с любым типом указателя. Если ваша система определяет макрос NULL с целочисленным типом, вам нужно добавить явное приведение. GCC заменяет stddef.h на копию, которая переопределяет NULL соответствующим образом.

В ANSI C NULL может быть либо 0, либо (void *)0, но только указатель удовлетворяет этому атрибуту, см. Также: В чем разница между NULL, '\ 0' и 0

Хотя 0 будет приведен к нулевому указателю с обычным аргументом указателя, невозможно дифференцировать нулевое целое от нулевого указателя с помощью vararg, поэтому различие имеет решающее значение. См .: продвижение аргумента по умолчанию для указателя

Верно, GCC гарантирует, что NULL будет указателем, а поскольку NCC предоставляется NULL в stddef.h (некоторые заголовки ANSI C находятся в GCC, другие - в glibc), я не уверен, что это может быть нарушено, поскольку sentinel - это расширение GCC для начала.

Но я бы все равно написал (void *)NULL или (void*)0 просто для уверенности.

Кроме того, для POSIX и man execl требуется "нулевой указатель" для завершения функции execl () , что является прототипом примера использования стража.

NULL не гарантированно будет работать там, потому что это «константа нулевого указателя», которая не обязательно является «нулевым указателем», поэтому при использовании (void *)0 везде вы более совместимы с хорошо известными API. См. Также: Является ли ((void *) 0) константой нулевого указателя? || Является ли (int *) 0 нулевым указателем?

GCC 5.2.0 предоставляет execl в качестве встроенного и устанавливает для него sentinel программно:

DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECL, "execl", BT_FN_INT_CONST_STRING_CONST_STRING_VAR, ATTR_SENTINEL_NOTHROW_LIST)

Существует также версия glibc 2.21 execl, которая не имеет атрибута.

2 голосов
/ 12 января 2014

Тривиальный пример:

#include <stdio.h>
#include <stdarg.h>

void print_strings(const char* first, ...) __attribute__((sentinel));

void print_strings(const char* first, ...)
{
    va_list ap;
    const char* tmp;
    if (!first)
        return ;
    printf("%s\n", first);
    va_start(ap, first);
    while (1) {
        tmp = va_arg(ap, const char*);
        if (tmp == 0)
            break;
        printf("%s\n", tmp);
    };
    va_end(ap);
}

int main()
{
    print_strings("how are you?", "i'm fine", "and you?", NULL);
    return 0;
}

В main, если вы вызываете print_strings как print_strings("how are you?", "I'm fine", "and you?"), у которого нет окончания NULL, GCC будет жаловаться на "отсутствующий страж".

Поскольку мы добавляем атрибут функции sentinel в функцию print_strings. Расширение gcc указывает, что аргументы переменной должны заканчиваться на NULL. Поэтому, если вы не заканчиваете аргументы переменных значением NULL, компилятор может обнаружить его и отобразить предупреждение.

1 голос
/ 29 декабря 2014

Вы можете передать NULL как: execl ("/ bin / bash", "ls", "- l", NULL); Последний параметр всегда должен быть 0. Это NULL терминатор . Поскольку список аргументов является переменным, мы должны иметь некоторый способ сообщить C, когда он должен закончиться.

1 голос
/ 24 февраля 2012

Sentinel означает охранять или защищать. Таким образом, в этом контексте происходит ошибка, потому что вы можете пропустить параметры защиты. Если вы используете массив или словарь, убедитесь, что после именования объектов вы заканчиваете их ключевым словом nil.

Пример:

[NSDictionary dictionaryWithObjectsAndKeys:@"UIAlertView", kSectionTitleKey,
              @"Show Custom", kLabelKey,
              @"AlertsViewController.m - alertOtherAction", kSourceKey];

Приведенный выше оператор выдаст ошибку «Отсутствует страж в вызове функции»

Правильный синтаксис:

[NSDictionary dictionaryWithObjectsAndKeys:@"UIAlertView", kSectionTitleKey,
              @"Show Custom", kLabelKey,
              @"AlertsViewController.m - alertOtherAction",kSourceKey,nil];
0 голосов
/ 24 сентября 2012

Я наконец нашел способ избавиться от этого странного и раздражающего предупреждения.

Все, что вам нужно сделать, это привести нулевой указатель к соответствующему типу указателя.

В случае UIAlertView это выглядит так:

UIAlertView* alert = [ [ UIAlertView alloc ] initWithTitle: @"Title" message: @"Message" delegate: nil cancelButtonTitle: @"Cancel" otherButtonTitles: @"OK", ( NSString* )nil ];

Обратите внимание на ( NSString* )nil приведение.

Попробуйте и дайте мне знать, если это работает для вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...