1

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.

5 Answers5

2

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.

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.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
1

First of all, match the types and the conversion specifiers.

  • sizeof yields a size_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.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • pretty sure I mentioned in the question - "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." ... dude, I literally asked why is this happening even without conversion? Also, You're right GCC allows incrementing void pointers and it is WRONG – Parth Rajawat Oct 08 '22 at 12:28
  • The conversion happens during the assignment. If the resulting objects are not aligned properly, attempting to access will result in undefined behaviour. – Sourav Ghosh Oct 08 '22 at 12:32
  • It's not a question of right or wrong. If you want strict conformance to the C standard (excluding compiler extensions) , you tell the compiler to use strict conformance. – Sourav Ghosh Oct 08 '22 at 12:33
  • Bascially, compiler automatically converts int to char ? – Parth Rajawat Oct 08 '22 at 12:35
  • No, there is no `int` to `char` conversion here. – Sourav Ghosh Oct 08 '22 at 12:35
  • I meant, int* to char* – Parth Rajawat Oct 08 '22 at 12:35
  • No, neither that. – Sourav Ghosh Oct 08 '22 at 12:45
  • what do you mean by this then ? – Parth Rajawat Oct 08 '22 at 13:06
1

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.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • I'm literally using a GCC compiler 9.4.0 version provided by linux. Which one are you using ? – Parth Rajawat Oct 08 '22 at 12:32
  • @ParthRajawat That's very strange. I wonder if your distro did something ill-advised with the defaults. See updated last paragraph in answer. – Steve Summit Oct 08 '22 at 12:36
  • @ParthRajawat I tried it with both gcc version 4.6.3 and 11.2.0 and got the same warning with both. – Steve Summit Oct 08 '22 at 13:00
  • No idea, what is happening? It has always been like this. even my non-void functions work without a return – Parth Rajawat Oct 08 '22 at 13:05
  • @ParthRajawat Are you invoking cc/gcc directly from the command line, or via a Makefile or other build system, or from within an IDE, or what? – Steve Summit Oct 08 '22 at 13:20
  • @ParthRajawat Also, I think there are ways of setting custom per-user or system-wide defaults for gcc. My hunch (though I could be completely wrong) is that one of those defaults is for whatever reason decreasing the warning level. If you explicitly invoke `gcc -Wincompatible-pointer-types`, does that change anything? – Steve Summit Oct 08 '22 at 13:23
  • I just solved the proble, look at my answer – Parth Rajawat Oct 08 '22 at 13:26
1

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.

0

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.
erenalyoruk
  • 121
  • 4