这是我的警告。
Missing sentinel in function call
我如何删除它。
我正在使用linux& gcc编译器。
答案 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
演员。
尝试一下,如果这对您有用,请告诉我。