C警告函数调用中缺少标记

时间:2010-03-09 08:40:53

标签: c warnings

这是我的警告。

Missing sentinel in function call

我如何删除它。

我正在使用linux& gcc编译器。

9 个答案:

答案 0 :(得分:62)

看起来您可能没有使用NULL终止数组声明。如果没有null,你可能会有一些内存怪异,因为运行时不知道数组的结束位置和下一位内存的开始。

答案 1 :(得分:46)

我刚遇到同样的问题。导致它的代码是......

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)。

答案 2 :(得分:18)

在Xcode中,如果使用objective-c进行编码,并且使用的是一些采用变量参数列表的方法,则需要在列表末尾添加 nil 对象。

例如:

N SArray * names = [NSArray arrayWithObjects:@“Name1”,@“Name2”]; //将导致上述警告

然而, NSArray * names = [NSArray arrayWithObjects:@“Name1”,@“Name2”,nil]; //正确

希望这会有所帮助!

答案 3 :(得分:10)

使用(void*)0(void *)NULL代替NULL

警告由Jichao提到的sentinel函数属性生成。记录于: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用一个适当重新定义NULL的副本替换stddef.h。

在ANSI C中,NULL可以是0(void *)0,但只有指针满足此属性,另请参阅:What is the difference between NULL, '\0' and 0

虽然使用常规指针参数将0转换为空指针,但是不可能将零指针的零整数与vararg区分开来,因此差异至关重要。请参阅:default argument promotion of pointer

是的,GCC保证NULL为指针,因为NULL由stddef.h中的GCC提供(某些ANSI C头在GCC中,其他在glibc中),我不确定这是否可以被破坏因为sentinel是GCC扩展的开头。

但为了确定,我仍然会写(void *)NULL(void*)0

此外,POSIX和man execl都需要execl() function终止的“空指针”,这是哨兵使用的典型示例。

NULL不能保证在那里工作,因为它是一个“空指针常量”,它不一定是“空指针”,因此通过在任何地方使用(void *)0,你都会与众所周知的更加一致蜜蜂。另见:Is ((void*)0) a null pointer constant? || Is (int *)0 a null pointer?

GCC 5.2.0提供execl as a built-in并以编程方式设置sentinel

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

还有一个execl的glibc 2.21版本没有该属性。

答案 4 :(得分:2)

一个简单的例子:

#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会抱怨“缺少哨兵”。

因为我们将sentinel函数属性添加到函数print_strings。它是一个gcc扩展,用于指定变量参数应以NULL结尾。因此,如果不使用NULL结束变量参数,编译器可以检测到它并显示警告。

答案 5 :(得分:1)

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

答案 6 :(得分:1)

您可以将NULL传递为: execl(&#34; / bin / bash&#34;,&#34; ls&#34;,&#34; -l&#34;,NULL); 最后一个参数必须始终为0.它是 NULL终止符。由于参数列表是可变的,我们必须有一些方法告诉C何时结束。

答案 7 :(得分:0)

您应将NULL作为函数的最后一个参数传递。

答案 8 :(得分:-1)

我终于找到了摆脱这种奇怪而烦人的警告的方法。

您需要做的就是将nil指针强制转换为适当的指针类型。

如果是UIAlertView,它会是这样的:

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

注意( NSString* )nil演员。

尝试一下,如果这对您有用,请告诉我。