I ran across a puzzling notation:
if(ptr != (void)(NULL)) {
//some action
}
So it expanded to
if(ptr != (void)((void *)0)) {
//some action
}
which seems at least strange.
Is there really any rationale behind that or is it simply pointless, or even wrong? It compiled fine, though (on linux / gcc, don't remember version).
-EDIT-
I checked that code today, and here's new info:
First of all, the casting was used in a macro, and it expanded to
return (void)((void*)0);
within a function returning void.
The code compiles using gcc (GCC) 4.1.2 20080704 on (Red Hat 4.1.2-50).
So, is this statement equivalent to
return void;
which is equivalent to
return;
or is there something more to that?
It likely should be a cast to a void pointer which is the same as just "pointer" (i.e. a pointer to any type):
if (ptr != (void *)(NULL)) {
...
}
Although the cast is unnecessary:
if (ptr != NULL) {
...
}
Your code doesn't even compile on my system (Mac with GCC 4.2.1), the error message GCC is reporting is void value not ignored as it ought to be. That's expected and because void means no value/type at all, and you can't compare that to anything else.
Here's what the C99 standard is saying:
§6.3.2.2 void
1 The (nonexistent) value of a void expression (an expression that has type void) shall not be used in any way, and implicit or explicit conversions (except to void) shall not be applied to such an expression. If an expression of any other type is evaluated as a void expression, its value or designator is discarded. (A void expression is evaluated for its side effects.)
§6.5.9 Equality operators
Constraints
2 One of the following shall hold:
both operands have arithmetic type;
both operands are pointers to qualified or unqualified versions of compatible types;
one operand is a pointer to an object or incomplete type and the other is a pointer to a qualified or unqualified version of void; or
one operand is a pointer and the other is a null pointer constant.
§6.3.2.2 already forbids the usage of void, and the constraints in §6.5.9 would also be violated.
So if a compiler would allow ptr != (void)(NULL) then it would violate the C99 standard. It might simply be a bug or misfeature of an older GCC version.
I only found a draft for C89, and here the void section is almost the same as in C99. But the section about the equality operators leaves me scratching my head. It seems to allow comparing to void, but this might be a mistake in the draft or a wording problem:
§3.2.2.2 void
The (nonexistent) value of a void expression (an expression that
has type void) shall not be used in any way, and implicit or explicit
conversions (except to void ) shall not be applied to such an
expression. If an expression of any other type occurs in a context
where a void expression is required, its value or designator is
discarded. (A void expression is evaluated for its side effects.)
§3.3.9 Equality operators
…
Constraints
One of the following shall hold:
both operands have arithmetic type;
both operands are pointers to qualified or unqualified versions of compatible types;
one operand is a pointer to an object or incomplete type and the other is a qualified or unqualified version of void ; or
one operand is a pointer and the other is a null pointer constant.
I have checked the assembly for this case.
Having such a function:
void x() {
return (void)(NULL);
}
Running preprocessor as: gcc x.c -E -o x.E -Wall -Wextra results in:
void x() {
return (void)(((void *)0));
}
Which seems rather bizzare. Anyway, after compiling it with gcc x.c -o x -Wall -Wextra, the assembly is (from objdump -d x):
0804841d <x>:
804841d: 55 push %ebp
804841e: 89 e5 mov %esp,%ebp
8048420: 90 nop
8048421: 5d pop %ebp
8048422: c3 ret
It's exactly the same as assembly for:
void x() {
return;
}
So these two expressions are equivalent.
I am using gcc version 4.8.2 (2013), for 64-bit linux, so it is not a bug of an old gcc version.
Adding -pedantic to gcc, however, makes it yield a warning:
warning: ISO C forbids ‘return’ with expression, in function returning void [-Wpedantic]
return (void)(NULL);
This happens for all of the dialects: c89, c99, gnu89, gnu99.
Related
Why this code:
extern void x;
leads to:
$ cl t555.c /std:c11 /Za
t555.c(1): error C2182: 'x': illegal use of type 'void'
What is illegal here?
UPD. Use case:
$ cat t555a.c t555.p.S
#include <stdio.h>
extern void x;
int main(void)
{
printf("%p\n", &x);
return 0;
}
.globl x
x:
.space 4
$ gcc t555a.c -std=c11 -pedantic -Wall -Wextra -c && as t555.p.S -o t555.p.o && gcc t555a.o t555.p.o && ./a.exe
t555a.c: In function ‘main’:
t555a.c:7:20: warning: taking address of expression of type ‘void’
7 | printf("%p\n", &x);
| ^
0x1004010c0
$ clang t555a.c -std=c11 -pedantic -Wall -Wextra -c && as t555.p.S -o t555.p.o && clang t555a.o t555.p.o && ./a.exe
t555a.c:7:20: warning: ISO C forbids taking the address of an expression of type 'void' [-Wpedantic]
printf("%p\n", &x);
^~
1 warning generated.
00007FF76E051120
This is an interesting case. It does not appear to violate any constraints to declare an identifier x of type void with external linkage, but it is nearly unusable.
void “is an incomplete object type that cannot be completed” (C 2018 6.2.5 19). When an identifier for an object is declared with no linkage, the type must “be complete by the end of its declarator” (6.7 7). But the same is not true for identifiers with external linkage; we can declare extern int a[]; extern struct foo b; and define a and b later, even in another translation unit.
If x is not used, I do not see that it violates any constraint. If the program attempted to use it, then 6.9 5 would apply:
… If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof or _Alignof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier; otherwise, there shall be no more than one.
But we cannot define x in C code because it has an incomplete type, and its type cannot be completed. As long as it is not defined, we cannot use x in an expression other than as the operand of sizeof or _Alignof, due the above paragraph, and neither can we use it with sizeof or _Alignof, because those operators require a complete type.
We could imagine that x is defined outside of C and linked with this C code. So some assembly module might provide a definition for x that is unknown to the C code. Of course, the C code cannot use the value of the object without having a definition for the type. But it could use the address of x. For example, it could serve as a sentinel or other token for pointer values. E.g., we could pass a list of lists of pointers to another routine as a list of pointers where the sublists were separated by &x and the end of the whole list was marked by a null pointer. (So two sublists (&a, &b, &c) and (&d, &e, &f) would be passed as (void *[]) { &a, &b, &c, &x, &d, &e, &f, NULL };.)
However, compiling printf("%p\n", &x); with Clang and using -pedantic produces the error message “ISO C forbids taking the address of an expression of type 'void'”. The core reason for this appears to be that 6.3.2.1 1 excludes an object of void type from being an lvalue:
An lvalue is an expression (with an object type other than void) that potentially designates an object;…
and 6.5.3.2 1 requires the operand of unary & to be an lvalue:
The operand of the unary & operator shall be either a function designator, the result of a [] or unary * operator, or an lvalue that designates an object…
This is likely an incompletely designed part of the C standard, as it does not preclude a const void from being an lvalue, and Clang compiles extern const void x; printf("%p\n", &x); without complaint, but there seems to be no reason for the standard to treat const void and void differently in this regard.
On the one hand, Microsoft may have concluded there is no way to use this x and so are issuing a diagnostic for it as soon as the extern void x is found rather than letting an error happen when code attempts to use this x. However, while a compiler is free to issue additional diagnostic messages, it ought to accept a conforming program. That is, for a compiler that conforms to the C standard, the diagnostic may be a warning but may not be an error that prevents compilation.
Supplementary Note
Noting that the constraint for unary & allows “the result of a [] or unary * operator”, I tested this:
static void foo(void *p)
{
printf("%p\n", &*p);
}
Here, *p by itself is an lvalue of type void, and this is allowed for & because the constraint specifically allows it, while &x would seem to be a very similar expression, taking the address of a void, but the constraint does not allow it since x is neither an lvalue nor a result of *. Curious.
I noticed C compilers (gcc, clang, tinycc) allow me to assign a pointer to a larger array to a pointer to a smaller VLA without a warning:
#include <stdio.h>
#if !__TINYC__
void take_vla(int N, char const X[1][N]) { printf("%zd\n", sizeof(*X)); }
#endif
int main()
{
static char bigarray[]="0123456789abcdefghijklmnopqrstuvwxyz";
//VLA
int n = 3;
char const (*subarray2)[n]=&bigarray;
//char const (*subarray3)[(int){3}]=&bigarray; //VLA but clang doesn't see it as such (a bug, I guess)
#if !__TINYC__
take_vla(3,&bigarray);
take_vla(3,&"abcdefg");
#endif
#if 0
char const (*subarray1)[3]=&bigarray; //-Wincompatible-pointer-types
#endif
}
Is this conformant C and why?
const char[3] is not compatible with char[37].
Nor is "pointer to qualified type" compatible with "pointer to type" - don't mix this up with "qualified pointer to type". (Const correctness does unfortunately not work with array pointers.)
The relevant part being the rule of simple assignment C17 6.5.16.1:
the left operand has atomic, qualified, or unqualified pointer type, and (considering
the type the left operand would have after lvalue conversion) both operands are
pointers to qualified or unqualified versions of compatible types, and the type pointed
to by the left has all the qualifiers of the type pointed to by the right;
Looking at various compilers:
gcc in "gnu mode" is useless for checking C conformance. You must compile with -std=cxx -pedantic-errors. After which gcc behaves fine: gcc -std=c17 -pedantic-errors:
error: pointers to arrays with different qualifiers are incompatible in ISO C [-Wpedantic]
icc gives the same diagnostics as gcc, it works fine.
Whereas clang -std=c17 -pedantic-errors does not report errors, so it apparently does not conform to the C standard.
In my answer I mention that dereferencing a void pointer is a bad idea. However, what happens when I do this?
#include <stdlib.h>
int main (void) {
void* c = malloc(4);
*c;
&c[0];
}
Compilation:
gcc prog.c -Wall -Wextra
prog.c: In function 'main':
prog.c:4:2: warning: dereferencing 'void *' pointer
*c;
^~
prog.c:5:4: warning: dereferencing 'void *' pointer
&c[0];
^
prog.c:5:2: warning: statement with no effect [-Wunused-value]
&c[0];
^
Here is an image from Wandbox for those who say it didn't happen:
and a Live demo in Ideone.
It will actually try to read what the memory that c points to has, and then fetch that result, but actually do nothing in the end? Or this line will simply have no effect (but then GCC wouldn't produce a warning).
I am thinking that since the compiler doesn't know anything about the data type, it won't be able to do much, without knowing the size of the type.
Why derefencing a void* does not produce an error, but just a warning?
If I try an assignment, I will get an error:
invalid use of void expression
but shouldn't the dereferencing alone produce an error?
The C standard explicitly states in 5.1.1.3p1:
A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined. Diagnostic messages need not be produced in other circumstances. 9)
With footnote 9 saying that
The intent is that an implementation should identify the nature of, and where possible localize, each violation. Of course, an implementation is free to produce any number of diagnostics as long as a valid program is still correctly translated. It may also successfully translate an invalid program.
So, GCC complies with the letter of the C standard. Your program is an invalid program. Only a diagnostics message is required - and the compiler is allowed to successfully translate your invalid program. As GCC has a non-standard extension for void pointer arithmetic:
In GNU C, addition and subtraction operations are supported on pointers to void and on pointers to functions. This is done by treating the size of a void or of a function as 1.
A consequence of this is that sizeof is also allowed on void and on function types, and returns 1.
The option -Wpointer-arith requests a warning if these extensions are used.
it decided that it might do something "sensible" with your invalid program and translated it successfully.
Notice that non-evaluated dereference of pointer-to-void is already required in sizeof, because:
void *foo;
sizeof *foo;
must match that of
sizeof (void);
They both evaluate to 1, so it is just easier allow the discarded dereference of pointers to void everywhere.
As Lundin says, if you want actual errors for constraint violations, use -std=c11 -pedantic-errors.
From C11 6.3.2.3 "void":
The (nonexistent) value of a void expression (an expression that has type void) shall not be used in any way, and implicit or explicit conversions (except to void) shall not be applied to such an expression. If an expression of any other type is evaluated as a void expression, its value or designator is discarded. (A void expression is evaluated for its side effects.)
So an expression can have void type, you just can't do anything with the result of that expression (such as assign it to something). *c is a valid expression that does nothing.
6.2.5/19 "Types"
The void type comprises an empty set of values; it is an incomplete object type that cannot be completed.
6.5.6/2 "Additive operators"
For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to a complete object type and the other shall have integer type.
And array subscripting is defined in terms of pointer arithmetic. So normally, the expression &c[0] would not be allowed.
GCC allows pointer arithmetic on (and therefore subscripting arrays of) void types as an extension.
The only reason this compiles is because you are using the wrong GCC options - you are not compiling this with a strictly conforming C compiler but with GCC extensions.
Compiled properly with -std=c11 -pedantic-errors, we get:
warning: dereferencing 'void *' pointer|
error: pointer of type 'void *' used in arithmetic [-Wpointer-arith]|
warning: dereferencing 'void *' pointer|
warning: statement with no effect [-Wunused-value]|
void pointer de-referencing and arithmetic are gcc extensions. When such non-standard extensions are enabled, void* is treated as uint8_t* in terms of arithmetic, but you still can't de-reference it, because it is regarded as an incomplete type still.
As for what GCC does with this code in non-standard mode, with no optimizations enabled (Mingw/x86), nothing terribly exciting happens:
0x004014F0 push %rbp
0x004014F1 mov %rsp,%rbp
0x004014F4 sub $0x30,%rsp
0x004014F8 callq 0x402310 <__main>
0x004014FD mov $0x4,%ecx
0x00401502 callq 0x402b90 <malloc>
0x00401507 mov %rax,-0x8(%rbp)
0x0040150B mov $0x0,%eax
0x00401510 add $0x30,%rsp
0x00401514 pop %rbp
0x00401515 retq
in gcc, it's possible to perform pointer arithmetic on void * pointers (How void pointer arithmetic is happening in GCC)
And it's even possible to print sizeof(void) which is 1.
Your example issues a warning, but the line does nothing (like when you ignore a parameter by doing (void)a to avoid the "unused parameter" warning).
Try assigning something and gcc will complain
void *c=malloc(4);
*c = 'a';
gives me 1 warning, and 1 error
test.c:9:3: warning: dereferencing 'void *' pointer
*c = 'a';
^~
test.c:9:3: error: invalid use of void expression
*c = 'a';
^
Or even use a volatile char cast on it:
test.c:9:3: error: invalid use of void expression
(volatile char)*c;
So you can dereference it, but you cannot use the dereferenced value (also tried reading/assigning it, no way: you get "void value not ignored as it ought to be")
EDIT: semi-valid example (lifted from memcpy: warning: dereferencing ‘void *’ pointer)
void *c=malloc(4);
void *d=malloc(5);
memcpy(d, &c[2], 2);
here you're dereferencing with an offset then you take the address again to get c+2 : that works because of gcc pointer arithmetic. Of course:
memcpy(d, ((char*)c)+2, 2);
is the way to avoid the warning and is compliant to the standard.
This is going to be a long, language lawyerish question, so I'd like to quickly state why I find it relevant. I am working on a project where strict standard compliance is crucial (writing a language that compiles to C). The example I am going to give seems like a standard violation on the part of clang, and so, if this is the case, I'd like to confirm it.
gcc says that a conditional with a pointer to a restrict qualified pointer can not co-inhabit a conditional statement with a void pointer. On the other hand, clang compiles such things fine. Here is an example program:
#include <stdlib.h>
int main(void){
int* restrict* A = malloc(8);
A ? A : malloc(8);
return 0;
}
For gcc, the options -std=c11 and -pedantic may be included or not in any combination, likewise for clang and the options -std=c11 and -Weverything. In any case, clang compiles with no errors, and gcc gives the following:
tem-2.c: In function ‘main’:
tem-2.c:7:2: error: invalid use of ‘restrict’
A ? A : malloc(8);
^
The c11 standard says the following with regard to conditional statements, emphasis added:
6.5.15 Conditional operator
...
One of the following shall hold for the second and third operands:
— both operands have arithmetic type;
— both operands have the same structure or union type;
— both operands have void type;
— both operands are pointers to qualified or unqualified versions of compatible types;
— one operand is a pointer and the other is a null pointer constant; or
— one operand is a pointer to an object type and the other is a pointer to a qualified or unqualified version of void.
...
If both the second and third operands are pointers or one is a null pointer constant and the
other is a pointer, the result type is a pointer to a type qualified with all the type qualifiers
of the types referenced by both operands. Furthermore, if both operands are pointers to
compatible types or to differently qualified versions of compatible types, the result type is
a pointer to an appropriately qualified version of the composite type; if one operand is a
null pointer constant, the result has the type of the other operand; otherwise, one operand
is a pointer to void or a qualified version of void, in which case the result type is a
pointer to an appropriately qualified version of void.
...
The way I see it, the first bold portion above says that the two types can go together, and the second bold portion defines the result to be a pointer to a restrict qualified version of void. However, as the following states, this type can not exist, and so the expression is correctly identified as erroneous by gcc:
6.7.3 Type qualifiers, paragraph 2
Types other than pointer types whose referenced type is an object type shall not be restrict-qualified.
Now, the problem is that a "shall not" condition is violated by this example program, and so is required to produce an error, by the following:
5.1.1.3 Diagnostics, paragraph 1
A conforming implementation shall produce at least one diagnostic message (identified in
an implementation-defined manner) if a preprocessing translation unit or translation unit
contains a violation of any syntax rule or constraint, even if the behavior is also explicitly
specified as undefined or implementation-defined. Diagnostic messages need not be
produced in other circumstances.
It seems clang is not standard compliant by treating an erroneous type silently. That makes me wonder what else clang does silently.
I am using gcc version 5.4.0 and clang version 3.8.0, on an x86-64 Ubuntu machine.
Yes it looks like a bug.
Your question more briefly: can void be restrict qualified? Since void is clearly not a pointer type, the answer is no. Because this violates a constraint, the compiler should give a diagnostic.
I was able to trick clang to confess its sins by using a _Generic expression
puts(_Generic(A ? A : malloc(8), void* : "void*"));
and clang tells me
static.c:24:18: error: controlling expression type 'restrict void *' not compatible with any generic association type
puts(_Generic(A ? A : malloc(8), void* : "void*"));
which shows that clang here really tries to match a nonsense type restrict void*.
Please file them a bug report.
While a compiler could satisfy all obligations surrounding restrict by ignoring the qualifier altogether, a compiler which wants to keep track of what it is or is not allowed to do needs to keep track of which pointers hold copies of restrict pointers. Given something like:
int *foo;
int *bar;
int wow(int *restrict p)
{
foo = p;
...
*p = 123;
*foo = 456;
*p++;
*bar = 890;
return *p;
}
since foo is derived from p, a compiler must allow for accesses made via
foo to alias accesses via p. A compiler need not make such allowances
for accesses made via bar, since that is known not to hold an address derived from p.
The rules surrounding restrict get murky in cases where a pointer may or
may not be derived from another. A compiler would certainly be allowed to
simply ignore a restrict qualifier in cases where it can't track all of
the pointers derived from a pointer; I'm not sure if any such cases would
invoke UB even if nothing ever modifies the storage identified by the
pointer. If a syntactic construct is structurally guaranteed to invoke
UB, having a compiler squawk may be more useful than having it act in an
arbitrary fashion (though having a compiler simply ignore any restrict
qualifiers it can't fully handle might be more useful yet).
What would this statement yield?
void *p = malloc(sizeof(void));
Edit: An extension to the question.
If sizeof(void) yields 1 in GCC compiler, then 1 byte of memory is allocated and the pointer p points to that byte and would p++ be incremented to 0x2346? Suppose p was 0x2345. I am talking about p and not *p.
The type void has no size; that would be a compilation error. For the same reason you can't do something like:
void n;
EDIT.
To my surprise, doing sizeof(void) actually does compile in GNU C:
$ echo 'int main() { printf("%d", sizeof(void)); }' | gcc -xc -w - && ./a.out
1
However, in C++ it does not:
$ echo 'int main() { printf("%d", sizeof(void)); }' | gcc -xc++ -w - && ./a.out
<stdin>: In function 'int main()':
<stdin>:1: error: invalid application of 'sizeof' to a void type
<stdin>:1: error: 'printf' was not declared in this scope
If you are using GCC and you are not using compilation flags that remove compiler specific extensions, then sizeof(void) is 1. GCC has a nonstandard extension that does that.
In general, void is a incomplete type, and you cannot use sizeof for incomplete types.
Although void may stand in place for a type, it cannot actually hold a value. Therefore, it has no size in memory. Getting the size of a void isn’t defined.
A void pointer is simply a language construct meaning a pointer to untyped memory.
void has no size. In both C and C++, the expression sizeof (void) is invalid.
In C, quoting N1570 6.5.3.4 paragraph 1:
The sizeof operator shall not be applied to an expression that
has function type or an incomplete type, to the parenthesized name of
such a type, or to an expression that designates a bit-field member.
(N1570 is a draft of the 2011 ISO C standard.)
void is an incomplete type. This paragraph is a constraint, meaning that any conforming C compiler must diagnose any violation of it. (The diagnostic message may be a non-fatal warning.)
The C++ 11 standard has very similar wording. Both editions were published after this question was asked, but the rules go back to the 1989 ANSI C standard and the earliest C++ standards. In fact, the rule that void is an incomplete type to which sizeof may not be applied goes back exactly as far as the introduction of void into the language.
gcc has an extension that treats sizeof (void) as 1. gcc is not a conforming C compiler by default, so in its default mode it doesn't warn about sizeof (void). Extensions like this are permitted even for fully conforming C compilers, but the diagnostic is still required.
Taking the size of void is a GCC extension.
sizeof() cannot be applied to incomplete types. And void is incomplete type that cannot be completed.
In C, sizeof(void) == 1 in GCC, but this appears to depend on your compiler.
In C++, I get:
In function 'int main()':
Line 2: error: invalid application of 'sizeof' to a void type
compilation terminated due to -Wfatal-errors.
To the 2nd part of the question: Note that sizeof(void *)!= sizeof(void).
On a 32-bit arch, sizeof(void *) is 4 bytes, so p++, would be set accordingly.The amount by which a pointer is incremented is dependent on the data it is pointing to. So, it will be increased by 1 byte.
while sizeof(void) perhaps makes no sense in itself, it is important when you're doing any pointer math.
eg.
void *p;
while(...)
p++;
If sizeof(void) is considered 1 then this will work.
If sizeof(void) is considered 0 then you hit an infinite loop.
Most C++ compilers choosed to raise a compile error when trying to get sizeof(void).
When compiling C, gcc is not conforming and chose to define sizeof(void) as 1. It may look strange, but has a rationale. When you do pointer arithmetic adding or removing one unit means adding or removing the object pointed to size. Thus defining sizeof(void) as 1 helps defining void* as a pointer to byte (untyped memory address). Otherwise you would have surprising behaviors using pointer arithmetic like p+1 == p when p is void*. Such pointer arithmetic on void pointers is not allowed in c++ but works fine with when compiling C with gcc.
The standard recommended way would be to use char* for that kind of purpose (pointer to byte).
Another similar difference between C and C++ when using sizeof occurs when you defined an empty struct like:
struct Empty {
} empty;
Using gcc as my C compiler sizeof(empty) returns 0.
Using g++ the same code will return 1.
I'm not sure what states both C and C++ standards on this point, but I believe defining the size of some empty structs/objects helps with reference management to avoid that two references to differing consecutive objects, the first one being empty, get the same address. If reference are implemented using hidden pointers as it is often done, ensuring different address will help comparing them.
But this is merely avoiding a surprising behavior (corner case comparison of references) by introduction another one (empty objects, even PODs consume at least 1 byte memory).