C警告在函数调用中缺less哨兵

这是我的警告。

Missing sentinel in function call 

我如何删除它。

我使用的是linux&gcc编译器。

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

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

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

但应该是…

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

第一个版本的问题是参数列表是以空指针结束的。 但'\ 0'不是一个空指针,它是一个空字符。 所以值(0)是正确的,只是types是错误的。

(char *)0也是零,但强制转换为char 指针 ,它是一个空指针(即指向地址0)。 这是必要的,所以系统可以知道参数列表结束的位置,以便在最后一个参数列表后不会继续扫描参数。 这样做会得到无效的指针,指向任何内存 – 这可能会导致分段错误。

那(char *)0被称为哨兵,这是第一个例子所缺less的。

最后注意NULL被定义为(void *)0,所以

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

工作也一样,而且更方便一些。 (感谢@mah)。

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

例如:

N SArray * names = [NSArray arrayWithObjects:@“Name1”,@“Name2”]; //会导致上面提到的警告

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

希望这会有所帮助!

使用(void*)0(void *)NULL来代替NULL作为标记。

警告是由Jichao提到的sentinel函数属性产生的。 logging在: https : //gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Function-Attributes.html#index-g_t_0040code_007bsentinel_007d-function-attribute-3226其中说:

任何指针types都将此上下文中的有效NULL定义为零。 如果你的系统用一个整数types定义了NULLmacros,那么你需要添加一个明确的转换。 GCC用适当重新定义NULL的副本replacestddef.h。

在ANSI C中,NULL可以是0(void *)0 ,只有指针满足这个属性,另请参见: NULL,'\ 0'和0之间的区别是什么

虽然0会被转换为带有常规指针参数的空指针,但是不可能用可变参数区分零指针的零整数,所以区别是至关重要的。 请参阅: 指针的默认参数提升

确实,GCC保证NULL是指针,并且由于stddef.h的GCC提供了NULL(一些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没有这个属性。

一个简单的例子:

 #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 ,海湾合作委员会将抱怨“失踪哨兵”。

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

哨兵意味着保护或保护..所以在这种情况下,错误发生,因为你可能会错误的防范参数。 如果你正在使用一个数组或字典,那么确保在命名你关键字为nil的对象后。

例:

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

上面的语句会产生一个错误“函数调用中缺less哨兵”

正确的语法:

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

你可以传递NULL作为:execl(“/ bin / bash”,“ls”,“ – l”,NULL); 最后一个参数必须总是0.它是一个NULL终止符 。 由于参数列表是可变的,我们必须有一些方式告诉C何时结束。

我终于find了摆脱这个奇怪而烦人的警告的方法。

你所要做的就是把一个零指针转换成一个合适的指针types。

UIAlertView情况下,它是这样的:

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

注意( NSString* )nil投。

试一试,让我知道这是否适合你。