Подтвердить что ты не робот

C Предупреждение о пропущенном контролере в вызове функции

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

Missing sentinel in function call

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

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

4b9b3361

Ответ 1

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

Ответ 2

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

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 за это).

Ответ 3

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

Например:

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

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

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

Ответ 4

Используйте (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 является указателем, а поскольку NULL предоставляется GCC в stddef.h (некоторые заголовки ANSI C находятся в GCC, другие - в glibc), я не уверен, что это может быть нарушено, так как sentinel - это расширение GCC для начала.

Но я все равно напишу (void *)NULL или (void*)0, чтобы быть уверенным.

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

NULL не гарантируется там, потому что это "константа нулевого указателя", которая не обязательно является "нулевым указателем", поэтому, используя (void *)0 везде, вы более совместимы с хорошо известными API. См. Также: Is ((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, которая не имеет атрибута.

Ответ 5

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

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

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

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

Ответ 6

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

Пример:

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

В приведенном выше предложении появится сообщение об ошибке "Отсутствие контролера в вызове функции"

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

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

Ответ 7

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

Ответ 8

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

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

В случае UIAlertView он выглядит примерно так:

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

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

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