So, I am practicing pointers in detail. I just studied that if we perform operations like -
int a = 1025;
int *ptr = &a;
printf("The size of integer is = %d\n", sizeof(int));
printf("The address = %d, value = %d\n", ptr, *ptr);
printf("The address = %d, value = %d\n", ptr 1, *(ptr 1));
char *pointer;
pointer = ptr;
printf("The size of character is = %d\n", sizeof(char));
printf("The address = %d, value = %d\n", pointer, *pointer);
printf("The address = %d, value = %d\n", pointer 1, *(pointer 1));
This should throw an error in pointer = ptr;
because they have a different type, and the way to make this work is by typcasting int *ptr
to (char*)ptr
.
But somehow, this is working without type casting and here is the output-
The size of integer is = 4
The address = 15647756, value = 1025
The address = 15647760, value = 15647756
The size of character is = 1
The address = 15647756, value = 1
The address = 15647757, value = 4
Why is this working, and not showing an error?
Also, we know that Void Pointers cannot be incremented, like we cannot do void pointer 1
but when I run this-
int a = 1025;
int *ptr = &a;
printf("The address = %d, value = %d\n", ptr, *ptr);
void *ptr1;
ptr1 = ptr;
printf("%d\n", ptr1 1);
It returns -
The address = 15647756, value = 1025
15647757
Clearly, the void pointer is getting incremented, which should NOT happen, Please explain this as well?
I am using gcc 9.4.0 version compiler on an 20.04 LTS ubuntu machine.
CodePudding user response:
This should throw an error in
pointer = ptr;
because they have a different type, and the way to make this work is by typcastingint *ptr
to(char*)ptr
.
You are correct inasmuch as C does not define behavior for assignment of a value of type int *
to an object of type char *
. This is because int *
and char *
are not "compatible" types, and neither is void *
.
Even interpreting "error" generously, however, there are few situations about which it is correct to say that a C implementation "should throw an error". These are the constraint violations, which C requires conforming implementations to diagnose. And that's all C requires in those situations. It does not require the implementation to reject the offending program, so if that's part of what "error" means to you then no, the C language specification provides no basis for saying that any particular code should throw an error.
Additionally, compilers do not necessarily diagnose all constraint violations by default. GCC is one that does not, but its -pedantic
option option requests that it emit all the diagnostics that the language standard requires of conforming implementations (among other things related to conformance to the standard). Or if you want GCC not only to diagnose but also to reject all code containing constraint violations then use -pedantic-errors
instead.
By default, GCC is happy to accept that assignment, and will interpret it as if the needed cast had been provided. This is an extension to standard C.
Also, we know that Void Pointers cannot be incremented, like we cannot do
void pointer 1
No. We know that the C language spec does not define behavior for arithmetic with void pointers. That's not the same thing. GCC, as another extension, does define such behavior, as equivalent to arithmetic on a char *
.
Relying on extensions such as these makes your programs less portable, but undefined behavior is undefined. You cannot rely on the compiler to reject such programs.
CodePudding user response:
First of all, match the types and the conversion specifiers.
sizeof
yields asize_t
type, use%zu
to print that.- use
%p
to print a pointer type.
That said, any other pointer type can be assigned (converted) to a char
pointer and accessed via the later, this is explicitly allowed. Quoting C11
, chapter 6.3.2.3,
...When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object.
The assignment should produce a warning, you might not have asked your compiler to show the warnings, and when you do, you can also ask the compiler to treat the warnings as errors, to see your desired outcome.
Finally, regarding the operation on void pointers, you're right, arithmetic operation on void pointer is not allowed as per C standard, but it might be allowed by a special provision in gcc, where it treats it equivalent to a char
pointer.
CodePudding user response:
You may have an issue with your compiler.
When I compile your code, I get the warning
warning: incompatible pointer types assigning to 'char *' from 'int *'
for the conversion you were asking about. Yes, normally conversion of an int *
to a char *
is illegal without a cast.
(I also got a bunch of warnings about mismatched printf
formats and arguments, because printing size_t
needs %zu
, and printing pointers requires %p
.)
If you're not getting these warnings, you might try increasing your compiler's warning level, perhaps with options like -Wall
or -Wextra
. Although it seems strange to me that you would have to, because in my experience, these warnings are enabled by default. gcc says "enabled by default". clang suggests that you can turn on this specific warning with -Wincompatible-pointer-types
, although for me it's enabled by default.
You also asked about arithmetic on void pointers. That's a popular, though controversial, gcc extension. See this question.
CodePudding user response:
Okay, So i Solved these issues. The thing was that the GCC compiler has inbuilt extensions, which allow
int a = 1025;
int *ptr = &a;
char *pointer;
pointer = ptr;
The GCC compiler also allows arithemetic on Void pointers because of another extension though this is NOT allowed by the C standard. Due to this extension, the Void pointers is treated as a char pointer.
For the GCC to show these errors as warnings, I added -Wall
flag in settings.json of my code-runner.
Next I added the -pedantic-errors
to my code-runner extension, and this flag caused the arithmetic on void pointers and illegal pointer assignment to become errors, and now the code does not run.
Hope it helps anyone, who encounters the same problem.
CodePudding user response:
From the latest C11 draft:
§7.16.1.1/2
...if type 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.