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
投。
试一试,让我知道这是否适合你。