This question already has answers here:
Is ((void *) -1) a valid address?
(3 answers)
Closed 5 years ago.
The function returns -1.
However, what is the meaning of (void*) in the following code:
can it work without it ?
test = shmat(shm_id, NULL, 0);
if (test == (void *)-1) {
/* handle shmat failure */
}
shmat has the following prototype:
void *shmat(int shmid, const void *shmaddr, int shmflg);
i.e. it returns a pointer to void, not an integer.
On error it will return the integer -1 cast to a pointer to void. From Linux manpages shmat(2):
On success, shmat() returns the address of the attached shared memory segment; on error, (void *) -1 is returned, and errno is set to indicate the cause of the error.
That is how you must do the comparison properly to check for an error return. The C11 standard says the following about the operator == in 6.5.9p5-6:
5 Otherwise, at least one operand is a pointer. If one operand is a pointer and the other is a null pointer constant, the null pointer constant is converted to the type of the pointer.
If one operand is a pointer to an object type and the other is a pointer to a qualified or unqualified version of void, the former is converted to the type of the latter.
6 Two pointers compare equal if and only if both are null pointers, both are pointers to the same object (including a pointer to an object and a subobject at its beginning) or function, both are pointers to one past the last element of the same array object, or one is a pointer to one past the end of one array object and the other is a pointer to the start of a different array object that happens to immediately follow the first array object in the address space.109)
That is, the standard defines behaviour for exactly 2 conversions: either one operand is a pointer to void, and the other operand is a pointer to something else; or one operand is a pointer, and the other operand is the null-pointer constant (i.e. 0, or (void*)0, or so). Since -1 without casts is neither a null-pointer constant, nor a pointer, the standard doesn't specify any behaviour for such case, thus the behaviour is undefined "by the omission of any explicit definition".
test == -1 is wrong, and test == (void *) -1 is right(ish).
As it turns out this is still a grey area. -1 is an int and on my computer, it is 32 bits. The conversion of an integer to pointer is defined by the implementation. The GCC manuals say:
A cast from pointer to integer discards most-significant bits if the pointer representation is larger than the integer type, sign-extends[2] if the pointer representation is smaller than the integer type, otherwise the bits are unchanged.
With footnote 2 saying
Future versions of GCC may zero-extend, or use a target-defined ptr_extend pattern. Do not rely on sign extension.
Thus it would mean that (void *)-1 might become incorrect too; the safer way would be to write it as (void *)(intptr_t)-1.
For some reason the (void *)0, i.e. the null pointer, is not used to signal an error condition (even though use of such a pointer in C would be erroneous standard-wise).
It is type casting.
The function shmat() returns a void*, so type casting is used to convert -1 (int) to the correct type (void*).
Actually, yes it could work but you'll get some warnings from the compiler.
Never ignore warnings they can hide bugs.
Related
The book Understanding and Using C Pointers, by Richard Reese says:
The null concept is an abstraction supported by the null pointer
constant. This constant may or may not be a constant zero. A C
programmer need not be concerned with their actual internal
representation.
My question is, since "this constant may or may not be a constant zero," is it safe for me to do things like the below in my code:
int *ptr = NULL;
// Some code which probably sets ptr to a valid memory address
if(!ptr)
{
ERROR();
}
If NULL is not 0, there is a chance that the if clause will evaluate to true.
Is it safe to assume that the NULL constant is zero?
NULL will compare equal to 0.
NULL is very commonly a zero bit pattern. It is possible for NULL to be a non-zero bit pattern - but not seen these days.
OP is mixing as least 4 things: NULL, null pointer constant, null pointer, comparing a null pointer to 0. C does not define a NULL constant.
NULL
NULL is a macro "which expands to an implementation-defined null
pointer constant" C17dr § 7.19 3
null pointer constant
An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant. C17dr § §
6.3.2.3 3
Thus the type of a null pointer constant may be int, unsigned, long, ... or void * .
When an integer constant expression1, the null pointer constant value is 0. As a pointer like ((void *)0), its value/encoding is not specified. It ubiquitously does have the bit pattern of zeros, but is not specified so.
There may be many null pointer constants. They all compare equal to each other.
Note: the size of a null pointer constant, when it is an integer, may differ from the size of an object pointer. This size difference is often avoided by appending a L or two suffix as needed.
null pointer
If a null pointer constant is converted to a pointer type, the
resulting pointer, called a null pointer, is guaranteed to compare
unequal to a pointer to any object or function. C17dr § § 6.3.2.3 3
Conversion of a null pointer to another pointer type yields a null
pointer of that type. Any two null pointers shall compare equal. C17dr
§ § 6.3.2.3 4
The type of null pointer is some pointer, either an object pointer like int *, char * or function pointer like int (*)(int, int) or void *.
The value of a null pointer is not specified. It ubiquitously does have the bit pattern of zeros, but is not specified so.
All null pointer compare as equal, regardless of their encoding.
comparing a null pointer to 0
if(!ptr) is the same as if(!(ptr != 0)). When the pointer ptr, which is a null pointer, is compared to 0, the zero is converted to a pointer, a null pointer of the same type: int *. These 2 null pointers, which could have different bit patterns, compare as equal.
So when it is not safe to assume that the NULL constant is zero?
NULL may be a ((void*)0) and its bit pattern may differ from zeros. It does compare equal to 0 as above regardless of its encoding. Recall pointer compares have been discussed, not integer compares. Converting NULL to an integer may not result in an integer value of 0 even if ((void*)0) was all zero bits.
printf("%ju\n", (uintmax_t)(uintptr_t)NULL); // Possible not 0
Notice this is converting a pointer to an integer, not the case of if(!ptr) where a 0 was converted to a pointer.
The C spec embraces many old ways of doing things and is open to novel new ones. I have never came across an implementation where NULL was not an all zeros bit pattern. Given much code exist that assumes NULL is all zero bits, I suspect only old obscure implementations ever used a non-zero bit-pattern NULL and that NULL can be all but certain to be an all zero bit pattern.
1 The null pointer constant is 1) an integer or 2) a void*. "When an integer ..." refers to the first case, not a cast or conversion of the second case as in (int)((void*)0).
if(!ptr) is a safe way to check for a NULL pointer.
The expression !x is exactly equivalent to 0 == x. The constant 0 is a NULL pointer constant, and any pointer may be compared for equality against a NULL pointer constant.
This holds true even if the representation of a null pointer is not "all bits 0".
Section 6.5.3.3p5 of the C standard regarding the ! operator states:
The result of the logical negation operator ! is 0 if the
value of its operand compares unequal to 0, 1 if the value of its
operand compares equal to 0. The result has type int. The
expression !E is equivalent to (0==E).
And section 6.3.2.3p3 regarding pointer conversions states:
An integer constant expression with the value 0, or such an
expression cast to type void *, is called a null pointer
constant. If a null pointer constant is converted to a pointer type,
the resulting pointer, called a null pointer, is guaranteed to compare
unequal to a pointer to any object or function.
chux has written a good, detailed answer, but regarding that book specifically, I'd be sceptic about its quality:
This constant may or may not be a constant zero
This is wrong, it must always be a zero or a zero cast to a void*. The definition of a null pointer constant is found in C17 6.3.2.3/3:
An integer constant expression with the value 0, or such an expression cast to type
void *, is called a null pointer constant. If a null pointer constant is converted to a
pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal
to a pointer to any object or function.
This means that all integer constant expressions like 0, 0L, 0u, 0x0, '\0' etc are null pointer constant. If any of them is cast to a void*, it is also a null pointer constant.
A C programmer need not be concerned with their actual internal representation.
The author is obviously mixing up the two formal terms null pointer constant and null pointer. A programmer do not need to concern themselves with the internal representation of a null pointer. They do need to know what makes a valid null pointer constant though. The safest, most readable way being to use the NULL macro, which is guaranteed to be a null pointer constant.
So regarding your question "is it safe for me to do things like the below in my code" - yes it is perfectly safe to do !ptr to check for a null pointer, even though ptr==NULL is more readable code.
From The Linux Programming Interface
execl(prog, arg, (char *) 0);
execl(prog, arg, (char *) NULL);
Casting NULL in the manner of the last call above is
generally required, even on implementations where NULL is
defined as (void *) 0.
This is because, although the C standards require that null pointers
of different types should test true for comparisons on equality, they
don’t require that pointers of different types have the same internal
representation (although on most implementations they do).
And, in a variadic function, the compiler can’t cast (void *) 0
to a null pointer of the appropriate type.
The C standards make one exception to the rule that pointers
of different types need not have the same representation: pointers
of the types char * and void * are required to have the same
internal representation. This means that passing (void *) 0
instead of (char *) 0 would not be a problem in the example case of
execl(), but, in the general case, a cast is needed.
"Casting NULL in the manner of the last call above is generally required"
Does the C standard requires the null pointer be represented the same as (char*) 0?
"in a variadic function such as execl(), the compiler can’t cast (void *) 0 to a null pointer of the appropriate type."
Is (void *) 0 not a null pointer of a type?
If yes, why can't the compiler cast (void *) 0 in execl(prog, arg, (void*) 0) to "a null pointer of the appropriate type"?
"pointers of the types char * and void * are required to have the same internal representation. This means that passing (void *) 0 instead of (char *) 0 would not be a problem in the example case of execl()".
Can the compiler cast (void *) 0 in execl(prog, arg, (void*) 0) to "a null pointer of the appropriate type" now?
Why does it contradict to the quote in my point 2?
If I replace (void *) 0 in execl(prog, arg, (void*) 0) with cast of 0 to any type's pointer, such as (int *) 0, can the compiler cast (int *) 0 in execl(prog, arg, (int*) 0) to "a null pointer of the appropriate type"?
Thanks.
For a non-variadic function call, such as in sigaction(SIGINT, &sa, (int*) 0), can the compiler cast (int *) 0 to "a null pointer of the appropriate type"?
Thanks.
Firstly, the compiler does not "cast" in any circumstance. A cast is a syntax construct in the source code which requests a conversion.
I will assume that when you talk about "the compiler casting" you mean to talk about implicit conversion which is the process whereby a value of one type may be converted to a value of another type, without a cast operator.
The Standard specifies precisely the contexts in which implicit conversion may be applied; there must always be a target type. For example in the code int x = Y; the expression Y can be some type that is not an int, but which has implicit conversion to int defined.
No implicit conversion is applied to function arguments that correspond to the ... part of a prototype, other than the default argument promotions. For pointer values, the default argument promotions leave them unchanged.
A common thread of your question seems to be that the compiler should somehow pretend that execl behaves as if there were a prototype in place for the last argument. But in fact there is not, and the compiler doesn't have any magic behaviour for specific functions. What you pass is what you get.
The standard specifies that the value of the expression (char *)0 is a null pointer. It says nothing about the representation of null pointers, and there may be multiple different representations that are all null pointers.
The execl function specification says that the argument list should be terminated by (char *)0 which is a value of type char *. A value of type void * is not a value of type char * and there are no implicit conversions in this context as discussed above.
There is still no implicit conversion; the text you quote is saying that you can use the wrong type argument in this one specific situation (no prototype parameter; and char * expected but void * provided, or vice versa).
That would be undefined behaviour , the text you quoted in point 3 does not apply to int *.
The sigaction function has a prototype; the parameter in question is struct sigaction *oldact. When you try to initialize a prototype parameter (or any variable) with a value of different type, implicit conversion to the type of the parameter is attempted. There is implicit conversion from any null pointer value to a null pointer value of a different type. This rule is in C11 6.3.2.3/4 . So that code is OK.
Since C99, the specification of va_arg reads in part
If [the type passed to va_arg as an argument] is not compatible with the type of the actual next argument (as promoted according to the default argument promotions), the behavior is undefined, except for the following cases:
one type is a signed integer type, the other type is the corresponding unsigned integer type, and the value is representable in both types;
one type is pointer to void and the other is a pointer to a character type.
The second bullet point means that, for any variadic function that uses va_arg to access its arguments, a call of the form
variadic_function("a", "b", "c", (void *)0);
will be valid whenever
variadic_function("a", "b", "c", (char *)0);
would have been.
There is, unfortunately, a catch: I can't find any requirement for variadic standard library functions1 to [behave as-if they] access their arguments by making a series of calls to va_arg. You're probably thinking, well, how else are they going to do it? In practice it's va_arg or hand-written assembly language, and maybe the committee didn't want to require the hand-written assembly language to be perfectly equivalent, but I wouldn't worry about it.
So the book you are quoting is technically incorrect. However, I would still write
execl(prog, arg, (char *) NULL);
if I was going to use NULL in the first place (I generally prefer to use 0 as the null pointer constant), because you shouldn't write code that relies on NULL expanding to ((void *)0), and
execl(prog, arg, 0);
is unquestionably incorrect. For example, execl will not receive a null pointer from that 0 on any ABI where int is 32 bits, char * is 64 bits, and int quantities are not sign- or zero-extended to 64 bits when passed as part of a variable argument list.
1 execl is not part of the C standard, but it is part of the POSIX standard, and any system providing execl in the first place is probably compliant with at least a subset of POSIX. All of clause 7.1.4 of the C standard can be assumed to apply to functions specified by POSIX as well.
1) Does the C standard requires the null pointer be represented the same as (char*) 0
Yes, since a null pointer constant has type void *, and because a void * and a char * have the same representation.
This is detailed in section 6.3.2.3p3 of the C standard:
An integer constant expression with the value 0, or such an
expression cast to type void * , is called a null pointer constant.
And section 6.2.5p28:
A pointer to void shall have the same representation and
alignment requirements as a pointer to a character type.
48)
...
48) The same representation and alignment requirements are
meant to imply interchangeability as arguments to functions,
return values from functions, and members of unions.
2) Is (void *) 0 not a null pointer of a type?
If yes, why can't the
compiler cast (void *) 0 in execl(prog, arg, (void*) 0) to "a null
pointer of the appropriate type"?
It is a null pointer of a type, and that type is void *.
The definition of execl is:
int execl(const char *path, const char *arg, ...);
So it can't cast the third parameter to the appropriate type because it doesn't know what the appropriate type is, but it doesn't matter because void * and char * are interchangeable per 6.2.4p28 and footnote 48 as mentioned above.
3) Can the compiler cast (void *) 0 in execl(prog, arg, (void*) 0)
to "a null pointer of the appropriate type" now?
Why does it contradict to the quote in my point 2?
It still can't cast because it doesn't know what the appropriate type is. But again, it doesn't matter because void * and char * are interchangeable.
4) If I replace (void *) 0 in execl(prog, arg, (void*) 0) with cast of
0 to any type's pointer, such as (int *) 0, can the compiler cast (int
*) 0 in execl(prog, arg, (int*) 0) to "a null pointer of the appropriate type"?
No, because again it doesn't know what the appropriate type is. And in this case you might have a problem if int * and char * don't have the same representation.
5) For a non-variadic function call, such as in sigaction(SIGINT, &sa, (int*) 0), can the compiler cast (int *) 0 to "a null pointer of the appropriate type"?
Yes, because (int *)0 is a null pointer, and because a null pointer can be converted to any other pointer.
AFAI understand that default argument promotion is applied to var-args functions except for pointers, which are remained as is done (zwol's example also supports1). So when 0 is passed to kinda var-args functions e.g. exec() family, it is recognized as unadorned integer 0 in lieu of null-pointer. En passant, execl(prog, arg, 0); may work on systems where null-pointer's internal representation and integer 0's internal representation are same yet it's not obligatory.
execl(prog, arg, NULL); may also unintentionally work subject to either of the following
If NULL is defined on the system as integer 0, the aforementioned
explanation is applied.
If NULL is defined on the system as null-pointer-constant as
(void*)0, though in a variadic function the compiler can't cast
(void*)0 to a null pointer of appropriate type, even since the C
standards say char* and void* are required to have same internal
representation.
For more, glance at here.
Additional exaple from here.
1 For example, execl will not receive a null pointer from that 0 on any ABI where int is 32 bits, char * is 64 bits, and int quantities are not sign- or zero-extended to 64 bits when passed as part of a variable argument list.
This could be thought of as an extension to this question (I'm interested in C only, but adding C++ to complete the extension)
The C11 standard at 6.3.2.3.3 says:
An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.
What my take on this personally is that 0 and (void *)0 represent the null pointer, whose integer value may not actually be 0, but that doesn't cover 0 cast to any other type.
But, the standard then continues:
If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, ...
which covers (int *)0 as null pointer since cast is an explicit conversion (C11, 6.3) which is listed under conversion methods.
However, what still makes me wonder is the following phrase
... or such an expression cast to type void * ...
With the above semantics, this phrase seems completely useless. The question is, is this phrase completely useless? If not, what implications does it have? Consequently, is (int *)0 the null pointer or not?
Another question that can help the discussion is the following. Is (long long)123 considered "123 converted to long long", or "123 with type long long". In other words, is there any conversion in (long long)123? If there is none, then the second quote above doesn't cover (int *)0 as a null pointer.
Short answer:
In both C and C++, (int *)0 is a constant expression whose value is a null pointer. It is not, however, a null pointer constant. The only observable difference between a constant-expression-whose-value-is-a-null-pointer and a null-pointer-constant, that I know of, is that a null-pointer-constant can be assigned to an lvalue of any pointer type, but a constant-expression-whose-value-is-a-null-pointer has a specific pointer type and can only be assigned to an lvalue with a compatible type. In C, but not C++, (void *)0 is also a null pointer constant; this is a special case for void * consistent with the general C-but-not-C++ rule that void * is assignment compatible with any other pointer-to-object type.
For example:
long *a = 0; // ok, 0 is a null pointer constant
long *b = (long *)0; // ok, (long *)0 is a null pointer with appropriate type
long *c = (void *)0; // ok in C, invalid conversion in C++
long *d = (int *)0; // invalid conversion in both C and C++
And here's a case where the difference between the null pointer constant (void *)0 and a constant-expression-whose-value-is-a-null-pointer with type void * is visible, even in C:
typedef void (*fp)(void); // any pointer-to-function type will show this effect
fp a = 0; // ok, null pointer constant
fp b = (void *)0; // ok in C, invalid conversion in C++
fp c = (void *)(void *)0; // invalid conversion in both C and C++
Also, it's moot nowadays, but since you brought it up: No matter what the bit representation of long *'s null pointer is, all of these assertions behave as indicated by the comments:
// 'x' is initialized to a null pointer
long *x = 0;
// 'y' is initialized to all-bits-zero, which may or may not be the
// representation of a null pointer; moreover, it might be a "trap
// representation", UB even to access
long *y;
memset(&y, 0, sizeof y);
assert (x == 0); // must succeed
assert (x == (long *)0); // must succeed
assert (x == (void *)0); // must succeed in C, unspecified behavior in C++
assert (x == (int *)0); // invalid comparison in both C and C++
assert (memcmp(&x, &y, sizeof y) == 0); // unspecified
assert (y == 0); // UNDEFINED BEHAVIOR: y may be a trap representation
assert (y == x); // UNDEFINED BEHAVIOR: y may be a trap representation
"Unspecified" comparisons do not provoke undefined behavior, but the standard doesn't say whether they evaluate true or false, and the implementation is not required to document which of the two it is, or even to pick one and stick to it. It would be perfectly valid for the above memcmp to alternate between returning 0 and 1 if you called it many times.
Long answer with standard quotes:
To understand what a null pointer constant is, you first have to understand what an integer constant expression is, and that's pretty hairy -- a complete understanding requires you to read sections 6.5 and 6.6 of C99 in detail. This is my summary:
A constant expression is any C expression which the compiler can evaluate to a constant without knowing the value of any object (const or otherwise; however, enum values are fair game), and which has no side effects. (This is a drastic simplification of roughly 25 pages of standardese and may not be exact.)
Integer constant expressions are a restricted subset of constant expressions, conveniently defined in a single paragraph, C99 6.6p6 and its footnote:
An integer constant expression96 shall have integer type and shall only have operands that are integer constants, enumeration constants, character constants, sizeof expressions whose results are integer constants, and floating constants that are the immediate operands of casts. Cast operators in an integer constant expression shall only convert arithmetic types to integer types, except as part of an operand to the sizeof
operator.
96 An integer constant expression is used to specify the size of a bit-field member of a structure, the value of an enumeration constant, the size of an array, or the value of a case constant. Further constraints that apply to the integer constant expressions used in [#if] are discussed in 6.10.1.
For purpose of this discussion, the important bit is
Cast operators ... shall only convert arithmetic types to integer types
which means that (int *)0 is not an integer constant expression, although it is a constant expression.
The C++98 definition appears to be more or less equivalent, modulo C++ features and deviations from C. For instance, the stronger separation of character and boolean types from integer types in C++ means that the C++ standard speaks of "integral constant expressions" rather than "integer constant expressions", and then sometimes requires not just an integral constant expression, but an integral constant expression of integer type, excluding char, wchar_t, and bool (and maybe also signed char and unsigned char? it's not clear to me from the text).
Now, the C99 definition of null pointer constant is what this question is all about, so I'll repeat it: 6.3.2.3p3 says
An integer constant expression with the value 0, or such an expression cast to type
void *, is called a null pointer constant. If a null pointer constant is converted to a
pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
Standardese is very, very literal. Those two sentences mean exactly the same thing as:
An integer constant expression with the value 0 is called a null pointer constant.
An integer constant expression with the value 0, cast to type void *, is also a null pointer constant.
When any null pointer constant is converted to a pointer type, the resulting pointer is called a null pointer and is guaranteed to compare unequal ...
(Italics - definition of term. Boldface - my emphasis.) So what that means is, in C, (long *)0 and (long *)(void *)0 are two ways of writing exactly the same thing, namely the null pointer with type long *.
C++ is different. The equivalent text is C++98 4.10 [conv.ptr]:
A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to zero.
That's all. "Integral constant expression rvalue of integer type" is very nearly the same thing as C99's "integer constant expression", but there are a few things that qualify in C but not C++: for instance, in C the character literal '\x00' is an integer constant expression, and therefore a null pointer constant, but in C++ it is not an integral constant expression of integer type, so it is not a null pointer constant either.
More to the point, though, C++ doesn't have the "or such an expression cast to void *" clause. That means that ((void *)0) is not a null pointer constant in C++. It is still a null pointer, but it is not assignment compatible with any other pointer type. This is consistent with C++'s generally pickier type system.
C++11 (but not, AFAIK, C11) revised the concept of "null pointer", adding a special type for them (nullptr_t) and a new keyword which evaluates to a null pointer constant (nullptr). I do not fully understand the changes and am not going to try to explain them, but I am pretty sure that a bare 0 is still a valid null pointer constant in C++11.
Evaluating the expression (int*)0 yields a null pointer of type int*.
(int*)0 is not a null pointer constant.
A null pointer constant is a particular kind of expression that may appear in C source code. A null pointer is a value that may occur in a running program.
C and C++ (being two distinct languages) have slightly different rules in this area. C++ doesn't have the "or such an expression cast to type void*" wording. But I don't think that affects the answer to your question.
As for your question about (long long)123, I'm not sure how it's related, but the expression 123 is of type int, and the cast specifies a conversion from int to long long.
I think the core confusion is an assumption that the cast in (int*)0 does not specify a conversion, since 0 is already a null pointer constant. But a null pointer constant is not necessarily an expression of pointer type. In particular, the expression 0 is both a null pointer constant and an expression of type int; it is not of any pointer type. The term null pointer constant needs to be thought of as a single concept, not a phrase whose meaning depends on the individual words that make it up.
NULL appears to be zero in my GCC test programs, but wikipedia says that NULL is only required to point to unaddressable memory.
Do any compilers make NULL non-zero? I'm curious whether if (ptr == NULL) is better practice than if (!ptr).
NULL is guaranteed to be zero, perhaps casted to (void *)1.
C99, §6.3.2.3, ¶3
An integer constant expression with the value 0, or such an expression cast to type
void *, is called a null pointer constant.(55) If a null pointer constant is converted to a
pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal
to a pointer to any object or function.
And note 55 says:
55) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant.
Notice that, because of how the rules for null pointers are formulated, the value you use to assign/compare null pointers is guaranteed to be zero, but the bit pattern actually stored inside the pointer can be any other thing (but AFAIK only few very esoteric platforms exploited this fact, and this should not be a problem anyway since to "see" the underlying bit pattern you should go into UB-land anyway).
So, as far as the standard is concerned, the two forms are equivalent (!ptr is equivalent to ptr==0 due to §6.5.3.3 ¶5, and ptr==0 is equivalent to ptr==NULL); if(!ptr) is also quite idiomatic.
That being said, I usually write explicitly if(ptr==NULL) instead of if(!ptr) to make it extra clear that I'm checking a pointer for nullity instead of some boolean value.
Notice that in C++ the void * cast cannot be present due to the stricter implicit casting rules that would make the usage of such NULL cumbersome (you would have to explicitly convert it to the compared pointer's type every time).
From the language standard:
6.3.2.3 Pointers
...
3 An integer constant expression with the value 0, or such an expression cast to type
void *, is called a null pointer constant.55) If a null pointer constant is converted to a
pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal
to a pointer to any object or function.
...
55) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.17.
Given that language, the macro NULL should evaluate to a zero-valued expression (either an undecorated literal 0, an expression like (void *) 0, or another macro or expression that ultimately evaluates to 0). The expressions ptr == NULL and !ptr should be equivalent. The second form tends to be more idiomatic C code.
Note that the null pointer value doesn't have to be 0. The underlying implementation may use any value it wants to represent a null pointer. As far as your source code is concerned, however, a zero-valued pointer expression represents a null pointer.
In practice is the same, but NULL is different to zero. Since zero means there's a value and NULL means there isn't any. So, theoretically they are different, NULL having a different meaning and in some cases that difference should be of some use.
in practice no, !ptr is correct
This is my warning.
warning: passing argument 2 of ‘memset’ makes integer from pointer without a cast
Then i changed as follows (make NULL to 0)
Before Change : memset(key, NULL, KEY_BYTES);
After Change : memset(key, 0, KEY_BYTES);
The warning is removed.
i am using linux & gcc compiler,C.
Is it correct action
Depending on implementation, the C standard library sometimes defines NULL as a zero integer (which would avoid the warning you saw) but sometimes defines NULL as zero cast into a void pointer. The latter implementation causes the warning you saw.
To answer your specific question, you should not be using NULL in this case. Regardless of the implementation, NULL is intended to be used as a null pointer, not a synonym for integer zero. If you want to use memset to fill a block of memory with zeroes, then pass zero as the second argument, not NULL.
Quoting from http://en.wikipedia.org/wiki/Stdlib.h:
NULL
The stdlib.h and stddef.h header files define
the macro NULL, which yields a null pointer
constant, and represents a pointer value that
is guaranteed not to point to a valid
address in memory.
Variants
NULL may be defined as a
constant expression equal to int zero,
long int zero, or zero cast to a void
* pointer:
#define NULL 0
#define NULL 0L
#define NULL ((void *) 0)
Although the null pointer constant is always
represented in C by the symbolic
constant 0 or by 0 cast to a void
pointer, the actual bit representation
of such a pointer is system-specific
and may contain one-bits.
Possibly NULL is defined as ((void*)0). Both versions work correctly, but the second looks better - memset requires a number and not a pointer.
The second parameter to memset is of type int. NULL is the null pointer constant in C. According to the standard:
An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.
So, NULL may be defined as (void *)0 or equivalent. In such a case, your memset call is wrong because you are converting a pointer to an integer.
The other way is okay: if you use 0 where a null pointer is expected, the compiler will do the conversion for you. So, given a type T, the following sets both p and q to the null pointer:
T *p = NULL;
T *q = 0;
Further, given a pointer p, the following are equivalent:
if (p) ...
if (p != NULL) ...
if (p != 0) ...
This is because 0 is special: in pointer contexts, it is automatically converted to the null pointer constant. A pointer on the other hand, is never converted to an integer implicitly. Any integer other than 0 is also never converted to a pointer implicitly.
Finally, in the code below, even though i has the value 0, it is not a null pointer constant in the assignment to p:
int i = 0;
int *p = i;
The above will trigger a warning when compiled in conformant mode.
(The above is a bit of a digression, but I hope it is not completely off-topic.)
Yes, they have the same effect. The compiler must be treating NULL as a special NULL pointer (whereas some more primitive compilers simply #define NULL 0), and the second parameter of memset is of type int, so by changing it to 0 you are using the null value but satisfying the int requirement.
memset accepts second argument as a character not any pointer.In your first call,you pass the NULL which is a pointer points to nothing in C.That's why,it gave error.In the second call,you 're assigning 0 bytes to the memory given.
When using memset(key, NULL, KEY_BYTES);
NULL is the (void*)0 {ie; void* typecasted of int zero}.
and the memset 2nd argument should be of type "unsigned int"
That is why it is showing warning.
Depending upon the compiler you are using it will behave.
Using gcc will make to warned (regarding data typecast) and will just accept nearest possible available value out of the given argument value.