address of a variable is assigned to integer variable without an error(just a warning) in C Language.how is this possible?? Can Anyone explain?
Code:
int main()
{
int a=9;
int *x=&a;
int y=&a;
printf("%d\n",y);
printf("%p",x);
return 0;
}
OUTPUT of the code:
test.c: In function 'main':
test.c:7:11: warning: initialization makes integer from pointer without a cast [-Wint-conversion]
int y=&a;
^
6422292
0061FF14
I am expecting an error in storing of address in integer variable.
how is this possible?? … I am expecting an error in storing of address in integer variable.
int y=&a; violates the constraints for simple assignment in C 2018 6.5.16.1 1, which list several combinations of types allowed for the right operands. The only combination in which the left operand has arithmetic type other than _Bool, as int does, says the right operand must also have arithmetic type, which &a does not:
… the left operand has atomic, qualified, or unqualified arithmetic type, and the right has arithmetic type…
C 2018 5.1.13 1 says what a conforming C implementation must do for this:
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,…
A warning is a diagnostic message. Therefore it satisfies the requirements of the C standard. This answers your question “how is this possible?”
Enable warnings in your compiler and elevate warnings to errors. With Clang, start with -Wmost -Werror. With GCC, start with -Wall -Werror. With MSVC, start with /W3 /WX.
how is this possible?
Because the compiler isn't obliged to do anything else but to give you a message of some form. See What must a C compiler do when it finds an error?
without an error(just a warning)
There is no such thing as "just a warning". A warning typically means: "here is a severe bug which you must fix to make your program behave as intended". It does not typically mean: "here is some minor cosmetic issue which you can ignore".
As for why your code isn't valid C, see "Pointer from integer/integer from pointer without a cast" issues.
As for what you should do to prevent lax compilers from generating an executable despite the code being invalid C, check out What compiler options are recommended for beginners learning C?
Related
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.
I can't seem to make sense of a GCC compiler warning I get when I try to assign a void * value to a intptr_t variable. Specifically, when I compile with -std=c99 -pedantic, I get the following warning regarding the initialization of variable z on line 7:
warning: initialization makes integer from pointer without a cast [-Wint-conversion]
Here is the source code:
#include <stdint.h>
int main(void){
unsigned int x = 42;
void *y = &x;
intptr_t z = y; /* warning: initialization makes integer from pointer without a cast [-Wint-conversion] */
return 0;
}
Naturally, if I explicitly cast y to intptr_t then the warning disappears. However, I confused why the warning is present for implicit conversions when the whole purpose of intptr_t is in the conversion and manipulation of void * values.
From section 7.18.1.4 of the C99 standard:
The following type designates a signed integer type with the property that any valid
pointer to void can be converted to this type, then converted back to pointer to void,
and the result will compare equal to the original pointer:
intptr_t
Am I misinterpreting the standard, or is GCC simply overly pedantic in its "integer from pointer" check in this case?
Summing up! Apologies in advance for any errors — please leave me a comment.
In C99:
Any pointer can be converted to an integer type.1
You might want to do that, e.g., if you are implementing your own operating system!
Conversions between pointers and integers can go horribly wrong,1 so are usually not what you want.
Therefore, the compiler warns you when you convert pointers to integers without casting. This is not overly pedantic, but to save you from undefined behaviour.
intptr_t (and uintptr_t, and likewise throughout) is just an integer type,2 so it is subject to the same risks as any other pointer-to-integer conversion. Therefore, you get the same warning.
However, with intptr_t, you at least know that the conversion from a pointer won't truncate any bits. So those are the types to use — with explicit casts — if you really need the integer values of pointers.
The spec1, #6 says that
... the
result is implementation-defined. If the result cannot be represented in the integer type,
the behavior is undefined.
With intptr_t, the result can be represented in the integer type. Therefore, the behaviour is not undefined, but merely implementation-defined. That is (as far as I know) why those types are safe to use for receiving values from pointers.
Edit
Reference 1, below, is part of section 6.3, "Conversions." The spec says:3
Several operators convert operand values from one type to another automatically. This
subclause specifies the result required from such an implicit conversion...
and refers to section 6.5.4 for a discussion of explicit casts. Therefore, the discussion in Reference 1 indeed covers implicit casts from any pointer type to intptr_t. By my reading, then, an implicit cast from void * to intptr_t is legal, and has an implementation-defined result.1, 4
Regarding whether the explicit cast should be used, gcc -pedantic thinks it should, and there must be a good reason! :) I personally agree that the explicit cast is more clear. I am also of the school of thought that code should compile without warnings if at all possible, so I would add the explicit cast if it were my code.
References
1C99 draft (since I don't have a copy of the final spec), sec. 6.3.2.3 #5 and #6).
2Id., sec. 7.18.1.4
3Id., sec. 6.3
4Id., sec. 3.4.1, defines "implementation-defined behavior" as "unspecified behavior where each implementation documents how the choice is made." The implication is that the conversion is legal, but that the result may be different on one platform than on another.
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).
Consider the following code (it came about as a result of this discussion):
#include <stdio.h>
void foo(int (*p)[]) { // Argument has incomplete array type
printf("%d\n", (*p)[1]);
printf("%d\n", p[0][1]); // Line 5
}
int main(void) {
int a[] = { 5, 6, 7 };
foo(&a); // Line 10
}
GCC 4.3.4 complains with the error message:
prog.c: In function ‘foo’:
prog.c:5: error: invalid use of array with unspecified bounds
Same error message in GCC 4.1.2, and seems to be invariant of -std=c99, -Wall, -Wextra.
So it's unhappy with the expression p[0], but it's happy with *p, even though these should (in theory) be equivalent. If I comment out line 5, the code compiles and does what I would "expect" (displays 6).
Presumably one of the following is true:
My understanding of the C standard(s) is incorrect, and these expressions aren't equivalent.
GCC has a bug.
I'd place my money on (1).
Question: Can anyone elaborate on this behaviour?
Clarification: I'm aware that this can be "solved" by specifying an array size in the function definition. That's not what I'm interested in.
For "bonus" points: Can anyone confirm that MSVC 2010 is in error when it rejects line 10 with the following message?
1><snip>\prog.c(10): warning C4048: different array subscripts : 'int (*)[]' and 'int (*)[3]'
Section 6.5.2.1 of n1570, Array subscripting:
Constraints
One of the expressions shall have type ‘‘pointer to complete object type’’, the other
expression shall have integer type, and the result has type ‘‘type’’.
So the standard forbids the expression p[0] if p is a pointer to an incomplete type. There is no such restriction for the indirection operator *.
In older versions/drafts of the standard, however, (n1256 and C99), the word "complete" is absent in that paragraph. Not being involved in any way in the standard procedure, I can only guess whether it's a breaking change or the correction of an omission. The behaviour of the compiler suggests the latter. That is reinforced by the fact that p[i] is per the standard identical to *(p + i) and the latter expression doesn't make sense for a pointer to an incomplete type, so for p[0] to work if p is a pointer to an incomplete type, an explicit special case would be needed.
My C is a bit rusty, but my reading is that when you have an int (*p)[] this:
(*p)[n]
Says "dereference p to get an array of ints, then take the nth one". Which seems naturally to be well defined. Whereas this:
p[n][m]
Says "take the nth array in p, then take the mth element of that array". Which doesn't seem well-defined at all; you have to know how big the arrays are to find where the nth one starts.
This could work for the specific special case where n = 0, because the 0th array is easy to find regardless of how big the arrays are. You've simply found that GCC isn't recognising this special case. I don't know the language spec in detail, so I don't know whether that's a "bug" or not, but my personal tastes in language design are that p[n][m] should either work or not, not that it should work when n is statically known to be 0 and not otherwise.
Is *p <===> p[0] really a definitive rule from the language specification, or just an observation? I don't think of dereferencing and indexing-by-zero as the same operation when I'm programming.
For your "bonus points" question (you probably should have asked this as a separate question), MSVC10 is in error. Note that MSVC only implements C89, so I have used that standard.
For the function call, C89 §3.3.2.2 tells us:
Each argument shall have a type such that its value may be assigned to
an object with the unqualified version of the type of its
corresponding parameter.
The constraints for assignment are in C89 §3.3.16:
One of the following shall hold: ... 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;
So we can assign two pointers (and thus call a function with a pointer parameter using a pointer argument) if the two pointers point to compatible types.
The compatibility of various array types is defined in C89 §3.5.4.2:
For two array types to be compatible, both shall have compatible
element types, and if both size specifiers are present, they shall
have the same value.
For the two array types int [] and int [3] this condition clearly holds. Therefore the function call is legal.
void foo(int (*p)[])
{
printf("%d\n", (*p)[1]);
printf("%d\n", p[0][1]); // Line 5
}
Here, p is a pointer to an array of an unspecified number of ints. *p accesses that array, so (*p)[1] is the 2nd element in the array.
p[n] adds p and n times the size of the pointed-to array, which is unknown. Even before considering the [1], it's broken. It's true that zero times anything is still 0, but the compiler's obviously checking the validity of all the terms without short-circuiting as soon as it sees zero. So...
So it's unhappy with the expression p[0], but it's happy with *p, even though these should (in theory) be equivalent.
As explained, they're clearly not equivalent... think of p[0] as p + 0 * sizeof *p and it's obvious why....
For "bonus" points: Can anyone confirm that MSVC 2010 is in error when it rejects line 10 with the following message?
1>\prog.c(10): warning C4048: different array subscripts : 'int ()[]' and 'int ()[3]'
Visual C++ (and other compilers) are free to warn about things that they think aren't good practice, things that have been found empirically to be often erroneous, or things the compiler writers just had an irrational distrust of, even if they're entirely legal re the Standard.... Examples that may be familiar include "comparing signed and unsigned" and "assignment within a conditional (suggest surrounding with extra parentheses)"