C warning Missing sentinel in function call
This is my warn开发者_运维技巧ing.
Missing sentinel in function call
How i can remove it.
i am using linux & gcc compiler.
It looks like you may not have terminated an array declaration with NULL
. Without the null you may have some memory weirdness as the runtime won't know where the array ends and the next bit of memory starts.
I just came across the same issue. The code which was causing it for me was...
execl("/bin/bash", "/bin/bash", fname, '\0');
but it should be...
execl("/bin/bash", "/bin/bash", fname, (char *)0);
The problem with the first version is that the list of parameters is meant to end with a null pointer. But '\0' is not a null pointer, it's a null character. So the value (0) is correct, it's just the type is wrong.
The (char *)0 is also zero, but cast as a char pointer, which is a null pointer (ie it points to address 0). This is needed so the system can tell where the parameter list ends so that it doesn't keep scanning for parameters after the last one. Doing that would get it invalid pointers which could point to any memory - which likely would cause a segmentation fault.
That (char *)0 is called the sentinel, and it's what was missing from the first example.
Finally note that NULL is defined as (void *)0, so
execl("/bin/bash", "/bin/bash", fname, NULL);
Works just as well, and is a little more convenient. (Thanks to @mah for that).
In Xcode if you are coding in objective-c and you are using some methods which take variable parameter list, you need to add nil object at the end of the list.
For example:
NSArray *names = [NSArray arrayWithObjects: @"Name1", @"Name2"]; //will result in the warning mentioned above
However, NSArray *names = [NSArray arrayWithObjects: @"Name1", @"Name2", nil]; //Correct
Hope this will help!
Use (void*)0
or (void *)NULL
instead of NULL
The warning is generated by the sentinel
function attribute as mentioned by Jichao. Documented at: https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Function-Attributes.html#index-g_t_0040code_007bsentinel_007d-function-attribute-3226 which says:
A valid NULL in this context is defined as zero with any pointer type. If your system defines the NULL macro with an integer type then you need to add an explicit cast. GCC replaces stddef.h with a copy that redefines NULL appropriately.
In ANSI C, NULL can be either 0
or (void *)0
, but only the pointer satisfies this attribute, see also: What is the difference between NULL, '\0' and 0
While 0
would be cast to null pointer with a regular pointer argument, it is impossible to differentiate the zero integer form the zero pointer with vararg, so the difference is crucial. See: default argument promotion of pointer
True, GCC guarantees NULL to be the pointer, and since NULL is provided by GCC in stddef.h
(some ANSI C headers are in GCC, others in glibc), I'm not sure if this could be broken since sentinel
is a GCC extension to start with.
But I'd still write (void *)NULL
or (void*)0
just to be sure.
Furthermore, both POSIX and man execl
require "a null pointer" for the execl() function termination which is a prototypical example of sentinel usage.
NULL
is not guaranteed to work there because it is a "null pointer constant", which is not necessarily "a null pointer", so by using (void *)0
everywhere you are more consistent with well known APIs. See also: Is ((void*)0) a null pointer constant? || Is (int *)0 a null pointer?
GCC 5.2.0 provides execl
as a built-in and sets sentinel
programmatically on it:
DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECL, "execl", BT_FN_INT_CONST_STRING_CONST_STRING_VAR, ATTR_SENTINEL_NOTHROW_LIST)
There is also a glibc 2.21 version of execl
which does not have the attribute.
A trivial example:
#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;
}
In main, if you call print_strings as print_strings("how are you?", "I'm fine", "and you?")
which has no ending NULL
, GCC will complain "missing sentinel".
Because we add the sentinel function attribute to the function print_strings
. It is a gcc extension to specify that the variable arguments should end with NULL. So if you do not end variable arguments with NULL, the compiler could detect it and show the warning.
You can pass NULL as: execl("/bin/bash", "ls","-l", NULL); The last parameter must always be 0. It is a NULL terminator. Since the argument list is variable we must have some way of telling C when it is to end.
Sentinel means to guard or protect.. So in this context the error is occuring cause you might be missng the guarding parameters. In case you are using an Array or Dictionary then make sure that after the naming the objects you end them with the keyword nil.
Example:
[NSDictionary dictionaryWithObjectsAndKeys:@"UIAlertView", kSectionTitleKey,
@"Show Custom", kLabelKey,
@"AlertsViewController.m - alertOtherAction", kSourceKey];
The above statement will produce an error "Missing sentinel in function call"
Correct syntax:
[NSDictionary dictionaryWithObjectsAndKeys:@"UIAlertView", kSectionTitleKey,
@"Show Custom", kLabelKey,
@"AlertsViewController.m - alertOtherAction",kSourceKey,nil];
You should pass NULL
as last argument of function.
I finally found a way to get rid of this strange and annoying warning.
All you need to do is to cast a nil pointer to an appropriate pointer type.
In case of UIAlertView
it goes like this:
UIAlertView* alert = [ [ UIAlertView alloc ] initWithTitle: @"Title" message: @"Message" delegate: nil cancelButtonTitle: @"Cancel" otherButtonTitles: @"OK", ( NSString* )nil ];
Notice the ( NSString* )nil
cast.
Have a try and let me know if this works for you.
精彩评论