6

In C++ when i do new (or even malloc) is there any guarantee that the return address will be greater than a certain value? Because... in this project i find it -very- useful to use 0-1k as a enum. But i wouldn't want to do that if its possible to get a value that low. My only target systems are 32 or 64bit CPUs with the OS window/linux and mac.

Does the standard say anything about pointers? Does windows or linux say anything about their C runtime and what the lowest memory address (for ram) is?

-edit- i end up modifying my new overload to check if the address is above >1k. I call std::terminate if it doesn't.

  • 1
    Why are you using enums as pointers? – Pubby Feb 12 '12 at 14:48
  • 1
    @Pubby: It’s common (particularly in interpreters and games) to rely on platform-specific pointer characteristics to stuff extra information into them, usually to eliminate indirection. Because of alignment rules, the bottom three bits are free; in addition, 64-bit systems generally have userspace pointers with only 48 significant bits; the rest are all `1` or `0`, so you can pack a pointer into the (53-bit) mantissa of a `double` with its upper bits set to represent `NaN`. Then the low-order flags let you quickly choose between representations with masking and shifting. – Jon Purdy Feb 12 '12 at 16:26
  • It appears i only need 6 bits so i won't even need the first 1 or 4k :). –  Feb 13 '12 at 05:08
  • You might want to check out [how Ruby stores values](https://stackoverflow.com/questions/75633126/how-is-value-in-ruby-sometimes-a-pointer-and-sometimes-not). They apparently assume that the first 3 bits are never set in a pointer. And that's just the beginning of the story. Supposedly this has something to do with alignment. – x-yuri Mar 04 '23 at 01:32

5 Answers5

6

In terms of standard, there is nothing. But in reality, it depends on the target OS, windows for instance reserves the first 64kb of memory as a no-mans land (depending on the build it is read-only memory, else it is marked as PAGE_NOACCESS), while it uses the upper 0x80000000+ for kernel memory, but it can be changed, see this & this on MSDN.

On x64 you can also use the higher bits of the address (only 47bits are used for addresses currently), but its not such a good idea, as later on it will change and your program will break (AMD who set the standard also advise against it).

Necrolis
  • 25,836
  • 3
  • 63
  • 101
4

There's no such guarantee. You can try using placement new if you need very specific memory locations but it has certain problems that you'll have to work hard to avoid. Why don't you try using a map with an integer key that has the pointer as its value instead? That way you wouldn't have to rely on specific memory addresses and ranges.

xxbbcc
  • 16,930
  • 5
  • 50
  • 83
2

In theory, no -- a pointer's not even guaranteed to be > 0. However, in practice, viewed as an unsigned integer (don't forget that a pointer may have a high-order "1" bit), no system that I know of would have a pointer value less than about 1000. But relying on that is relying on "undefined behavior".

Hot Licks
  • 47,103
  • 17
  • 93
  • 151
  • 1
    reference? I think I recall reading that the first 1GB in linux virtual memory is only for the kernel, [so if it is true, your application will not get an address in the first 1GB, unless it runs on kernel mode] However, I might be wrong about the initial assumption, I cannot remember where I think I read it :\ – amit Feb 12 '12 at 14:47
  • @amit my google-fu came up with this http://linux-mm.org/HighMemory "3GB for user programs and 1GB for the kernel" –  Feb 12 '12 at 14:58
  • @amit -- I was speaking very generally -- C++ runs on some pretty small systems. – Hot Licks Feb 12 '12 at 15:10
  • On Linux, the kernel-user space division is configurable in the kernel, so at least the 3 splits: 1-3 GB, 2-2 GB and 3-1 GB are common on 32-bit systems. This links is somewhat old but quite detailed: http://kerneltrap.org/node/2450 – Michał Kosmulski Feb 25 '12 at 18:29
1

There is no standard for where valid memory addresses come from; to write safe system-independent code, you cannot rely on certain addresses (and even with anecdotal support, you never know when that will change with a new system update).

mah
  • 39,056
  • 9
  • 76
  • 93
1

It's very platform-specific, so I would discourage relying on this kind of information unless you have a very good reason and are aware of consequences for portability, maintainability etc.

NULL is guaranteed to be 0x0 always. If I recall correctly, x86 reserves the first 128 MB of address space as "NULL-equivalent", so that valid pointers can't take on values in this range. On x64 there are some additional addresses which you shouldn't encounter in practice, at least for now.

As for address space reserved for the operating system, it will clearly depend on the OS. On Linux, the kernel-user space division is configurable in the kernel, so at least the 3 splits: 1-3 GB, 2-2 GB and 3-1 GB are common on 32-bit systems. You can find more details on kerneltrap.

Michał Kosmulski
  • 9,855
  • 1
  • 32
  • 51
  • Surely you meant the first 128 *K* B of address space? – Cody Gray - on strike May 20 '13 at 13:27
  • @CodyGray No, it's actually 128 MB, not kB. But I was not quite right about the causes. It's not caused by the CPU itself but rather by the layout of applications' address space on most UNIX-like systems. The area 0-128 MB is reserved for the stack, meaning you don't get addresses from this range when using `new` or `malloc()` which allocate memory from the heap. It's explained very well in [this nice answer](http://stackoverflow.com/a/2187753/1224016). – Michał Kosmulski May 22 '13 at 17:36