1

From https://stackoverflow.com/a/2761494/156458

neither C nor C++ provides a strictly defined feature that would allow you to assign a specific physical address to a pointer. So your question about "how one would assign 0 address to a pointer" formally has no answer. You simply can't assign a specific address to a pointer in C/C++. However, in the realm of implementation-defined features, the explicit integer-to-pointer conversion is intended to have that effect. So, you'd do it as follows

uintptr_t address = 0;
void *p = (void *) address;

Note, that this is not the same as doing

void *p = 0;

The latter always produces the null-pointer value, while the former in general case does not. The former will normally produce a pointer to physical address 0, which might or might not be the null-pointer value on the given platform.

I am surprised to find it out that void *p = 0 doesn't assign either physical or virtual address 0 but a null pointer of void to the pointer.

The quote also says that the "explicit integer-to-pointer conversion" can assign an address to a pointer.

Questions:

  1. in void *p = 0, is there implicit conversion from 0 to void*?

    Is the implicit conversion the same as explicit conversion (void *)0, i.e. is void *p = 0 the same as void *p = (void*) 0?

    Does void *p = (void*) 0 produce a pointer to either physical or virtual address 0 or a null pointer of void?

  2. If I use a nonzero number, e.g. void *p = 123, is there implicit conversion from 123 to void *?

    Is the implicit conversion the same as explicit conversion (void *) 123?

    Will either void *p = 123 or void *p = (void *)123 make p a pointer to either physical or virtual address 123?

    If void *p = (void *)123 can't generate a pointer to either physical or virtual address 123, can int addr = 123; void *p = (void *)addr;? I create it by replacing unitptr_t with int in the first example in the quote.

Thanks.

Tim
  • 1
  • 141
  • 372
  • 590
  • 1
    That's more than 1 question – Tim Randall Sep 06 '18 at 15:03
  • "Null" doesn't have to mean address-location `0` (physical or virtual). There have historically been systems where "null" was a special value different from the integer `0`. ***Also*** think about embedded systems where you might actually need to use the address `0`, as opposed to "null" – Some programmer dude Sep 06 '18 at 15:03
  • 1
    What sort of system are you working on that you have access to physical addresses? Most non-embedded systems deal with virtual addresses, not physical addresses — you have to be in the bowels of the memory management in the kernel to manipulate physical addresses. – Jonathan Leffler Sep 06 '18 at 15:04
  • @JonathanLeffler Thanks. I am not working on embeded system, and probably mean virtual address, so I change the question to about "either physical or virtual address". The answer I linked mentions "physical address" all the time, which has influenced my question, and why does it not use virtual address instead? – Tim Sep 06 '18 at 15:07
  • @JonathanLeffler: Yes; and when you are in the bowels of memory management in the kernel you want to use a plain integer type (e.g. `uint64_t`) for physical addresses for multiple reasons (easier bit twiddling, wanting compiler to complain about type mismatches if you try to set a pointer to a physical address, physical addresses being a different size to virtual addresses). – Brendan Sep 06 '18 at 15:12
  • The answer you refer to misuses the term “physical address.” Its statements are applicable to whatever addressing the C implementation is using, whether it is physical or virtual. It should not have used that term. There is nothing about conversions from integers to pointers that enables use of physical addresses when the program is running in a virtual address space. – Eric Postpischil Sep 06 '18 at 15:12
  • For many people, there are just 'addresses', and the 'virtual' and 'physical' qualifiers are omitted. The answer you link to seems to be working in terms of the address space within a C++ program. That would be more a logical address or virtual address when needing to distinguish between physical and virtual addresses. I'd be willing to argue that the answer is misusing 'physical address'. – Jonathan Leffler Sep 06 '18 at 15:13
  • *`void *p = 0;` The latter always produces the null-pointer value* More precisely, that produces **a** null-pointer value, not **the** null-pointer value. That was added later to C (C99, maybe?) as a sop to poor coding practices that assumed `NULL` meant zero. Note that the linked answer concerns C++ also, which IIRC has always treated an integer constant zero as a null pointer value. – Andrew Henle Sep 06 '18 at 15:27

2 Answers2

3

If you say

char *p = 0x12345;

you will probably assign p to point to address 0x12345. Whether that's a virtual or a physical address we can't say; that depends on your machine and how it's configured. (But if your machine uses virtual memory, and if you're writing an ordinary user program, then it's certainly a virtual address.)

In the above I said "probably", in part because assigning an integer to a pointer is not, strictly speaking, well-defined. So to be on the safe side, you would write

char *p = (char *)0x12345;

This will, again, assign p to point to address 0x12345.

But then we come to the special cases. If you write

char *p = 0;

or

char *p = (char *)0;

the question is, have you assigned p to point to address 0? And the answer is, probably, on any conventional machine, but this is not guaranteed, because there's a special case for null pointers.

It's not that p = 0 will not assign p to point to address 0 -- it's that it might not. On a machine where the internal representation of a null pointer is not all-bits-0, the assignment p = 0 will set p to that null pointer value, and p will therefore not point to address 0.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Steve Summit
  • 45,437
  • 7
  • 70
  • 103
2

TL;DR: Most of what you are asking about is in the realm of implementation-specific behavior and language extensions. Consult your compiler documentation if you have genuine need for such behaviors.

  1. in void *p = 0, is there implicit conversion from 0 to void*?

The initialization is non-conforming, but many compilers accept it as an extension. Those that do define the result however they want, but in practice they indeed provide an implicit conversion to void *.

Because literal 0 is a "null pointer constant", because initializers perform the same conversions that simple assignment does, and because simple assignment has a special-case provision for assigning null pointer constants to pointers, yes, 0 is implicitly converted to type void *. Furthermore, because 0 is a null pointer constant, such a conversion results in a null pointer of type void *.

Is the implicit conversion the same as explicit conversion (void *)0, i.e. is void *p = 0 the same as void *p = (void*) 0?

There is good reason to expect that a compiler that accepts the former form will treat it exactly the same as the latter form, but again, the former is non-conforming and implementations that accept it as an extension define their own semantics for it.

Yes. C nowhere distinguishes between the effects of conversions specified explicitly via casts and automatic conversions between the same types.

Does void *p = (void*) 0 produce a pointer to either physical or virtual address 0 or a null pointer of void?

It initializes p to contain a null pointer (of type void *). According to C, a null pointer does not point to any object, and C has no sense of addresses apart from those of objects or functions, so in at least this sense it is incorrect to interpret such a pointer as pointing to any particular address. The effect of dereferencing such a pointer is not defined by C, but it might be defined by some implementations -- possibly to attempt to access an object at address 0.

  1. If I use a nonzero number, e.g. void *p = 123, is there implicit conversion from 123 to void *?

That initialization is non-conforming, but some compilers provide an implicit conversion as an extension.

Is the implicit conversion the same as explicit conversion (void *) 123?

There is very good reason to expect that to be the case with a compiler that implements such an implicit conversion at all, but again, "extension".

Will either void *p = 123 or void *p = (void *)123 make p a pointer to either physical or virtual address 123?

That is implementation-defined. Again, C has no sense of addresses apart from those of objects or functions, and in particular it itself declines to specify the result of converting an integer to a pointer type, except for integers obtained by converting a pointer to integer in the first place, and for integer constant expressions with value 0.

On some implementations, however, converting an integer (other than an integer constant with value 0) to a pointer has the effect of interpreting the integer as an address, and converting to a pointer to that address, as if there were an object with that address. In a hosted C implementation, this will typically be a virtual address. In a standalone implementation, it will typically be a physical address. Some of implementations may extend this behavior to integer constants with value 0, too, which may or may not be inherently non-conforming.

If void *p = (void *)123 can't generate a pointer to either physical or virtual address 123, can int addr = 123; void *p = (void *)addr;? I create it by replacing unitptr_t with int in the first example in the quote.

There is every reason to expect that the result of explicitly converting an int variable with value 123 is exactly the same as that of explicitly converting an integer constant with value 123, but, technically, that it is implementation defined may leave room for conforming compilers to distinguish.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • `void *p = 0` should be perfectly valid, as `0` is a null pointer constant per [6.3.2.3p3](https://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p3) (That sure seems to be coming up a lot today...) – Andrew Henle Sep 06 '18 at 16:33
  • Actually, @AndrewHenle, I considered that before answering, and concluded that, paradoxically, a null pointer constant of the form `0` is not, itself, a pointer. In particular, 6.3.2.3/3 says "***If a null pointer constant is converted to a pointer type***, the resulting pointer, called a null pointer [...]" (emphasis added). It follows from the standard's requirement for a conversion that the `0` form without a cast does not have a pointer type, and as such is not directly assignable to a pointer. – John Bollinger Sep 06 '18 at 16:44
  • IMO 6.3.2.3p3 could be improved upon. My reading of that entire paragraph would be to make `0` and `(void *)0` essentially equivalent (and distinctly different from something like `(int *)0`). Given the paragraph is a force-fitted hack to allow for bad code that assumed `NULL` to be `0`, there probably isn't really a clean way to interpret it. – Andrew Henle Sep 06 '18 at 17:45
  • I guess we disagree then, @AndrewHenle. I think the interpretation is pretty clean and direct that `0` is a null pointer constant whose type is `int`, that `(void*)0` is a null pointer constant whose type is `void *`, and also a null pointer of type `void *`, and that both obey all the rules for their respective types, with the exceptions following from them both being null pointer constants. I note, too, that 7.19/3 specifies that `NULL` expands to an *implementation-defined* null pointer constant. If the null pointer constants are equivalent then why is implementation-definedness needed? – John Bollinger Sep 06 '18 at 18:11
  • @AndrewHenle, upon further analysis, although I still disagree about the general equivalence of `0` and `(void *)0`, I find that that makes less difference than I previously asserted. I have updated the relevant section of my answer, in case you are interested in the details. – John Bollinger Sep 06 '18 at 19:08