3

I don't understand what this line does:

((struct Example*) 0x10000)

I've written a test program:

#include <stdio.h>

struct Elf{
    int bla;
    char bla2;
};

int main(){
    struct Elf *elfPtr;
    printf("Before casting: %p\n", elfPtr);
 
    elfPtr = ((struct Elf *)0x10000);
    printf("After casting: %p\n", elfPtr);
 
    return 0;
}

The output is:

Before casting: 0xb776dff4

After casting: 0x10000

Does this line only do this?

elfPtr = 0x10000
Community
  • 1
  • 1
  • before cast it is printing a garbage address, additionally to use `%p` correct cast is `void*`.so `printf("After casting: %p\n", elfPtr);` should be written as `printf("After casting: %p\n", (void*)elfPtr);` correctly. – Grijesh Chauhan Sep 29 '13 at 12:08
  • The first `printf()` invokes undefined behaviour as `elfPtr` had not been initialised. – alk Sep 29 '13 at 12:09
  • @alk are you sure that examining an uninitialized pointer is undefined behavior? I think that the value is undefined, but not the behavior (i.e. it will have a value, and that value will not change). – pburka Sep 29 '13 at 12:13
  • @pburka: Yes, accessing an uninitialised variable invokes undefined behaviour. Allthough from my experiences it never caused any problems, besided the fact one gets random data. – alk Sep 29 '13 at 12:16
  • @alk you're right. Don't know what I was thinking. – pburka Sep 29 '13 at 12:20

4 Answers4

5

This does set the pointer to a specific constant value, which is a bad idea in systems with virtual memory management.

One notable exception is embedded systems with memory-mapped resources. In systems like that, hardware designers often reserve a range of memory addresses for alternative use, giving the programmer access to hardware registers as if they were part of the regular memory space.

Here is an example *:

struct UART {
    char data;
    char status;
};
const UART *uart1 = 0xC0000;
const UART *uart2 = 0xC0020;

With this setup in place, an embedded program can access UART's registers as if they were struct's members:

while (uart1->status & 0x02) {
    uart1->data = 0x00;
}


* UART stands for Universal Asynchronous Receiver/Transmitter, a piece of hardware commonly used for asynchronous peer-to-peer communication.
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 1
    Good answer, to print with `%p` we should cast address to `void*` else it is Undefined behaviour, Correct? – Grijesh Chauhan Sep 29 '13 at 12:27
  • 1
    @GrijeshChauhan Correct, `%p` expects a `void*`, otherwise it's a UB. – Sergey Kalinichenko Sep 29 '13 at 12:28
  • 1
    @GrijeshChauhan: For `char *` no casting is necessary. – alk Sep 30 '13 at 10:09
  • @alk Nice!..Only the cause?, do you know reason? may be because `sizeof(char*)` * `n` = `sizeof(void*)` but it is my fuzzy guess. – Grijesh Chauhan Sep 30 '13 at 10:14
  • 1
    @GrijeshChauhan: If I remember correctly the C-standard allows this for backward compatibilty to times where there was no `void` data type and with it obviously no `void *`. So the common type to genericly reference memory/objects was to use `char *`. – alk Sep 30 '13 at 10:19
  • @alk No I am unaware of this Thanks for the information Alk can you give me some link to read about it? – Grijesh Chauhan Sep 30 '13 at 10:37
  • 1
    @GrijeshChauhan: I think in (n1256) it's under 6.5.2.2/6 at the very end. It's about default argument promotion. – alk Sep 30 '13 at 11:32
  • why `(void *)-1` gives `0xffffffffffffffff` while `(void *)1` gives 0x1, I used `printf("%p\n",(void *)-1);` `printf("%p\n",(void *)1);` ? – Zzz0_o Aug 13 '20 at 18:14
  • @Zzz0_o Because your system uses 64-bit pointers and [two's complement](https://en.wikipedia.org/wiki/Two%27s_complement) representation of negative integer values. – Sergey Kalinichenko Aug 13 '20 at 18:24
  • thanks a lot dasblinkenlight, i see some code like this `(unsigned long)(void *)-1`, does it make sense to cast this particular to `unsigned long` because `(void *)-1` is an address which is already positive ? – Zzz0_o Aug 15 '20 at 04:51
  • @Zzz0_o A cleaner approach to do integer operations on pointers is with [`uintptr_t`](https://stackoverflow.com/q/1845482/335858). – Sergey Kalinichenko Aug 15 '20 at 11:00
  • but `(void *)-1` is already an address, a positive number so why do we need `(unsigned long)` cast on first place ? – Zzz0_o Aug 15 '20 at 15:22
  • @Zzz0_o Although `(void*)` has a digital representation that can be interpreted as a number, it is not a full-featured number, in the sense that you cannot perform numeric operations on it. That's why you cannot say whether it is positive or negative: you need to cast it to a numeric pointer type `intptr_t` or `uintptr_t` to make it a signed or an unsigned number. – Sergey Kalinichenko Aug 15 '20 at 16:53
  • thanks a lot for the explanation @dasblinkenlight Not it makes sense to me :-) – Zzz0_o Aug 15 '20 at 19:13
2

Normally, assigning an arbitrary value to a pointer is a bad idea. That's why the compiler discourages it, and you need to add the cast to reassure the compiler that you know what you're doing.

(Your code is going to treat the memory at address 0x10000 as a struct Elf instance, and at least in your simple example, it's not. It might not even be readable and/or writable memory, so you'll get a crash when you try to access it.)

RichieHindle
  • 272,464
  • 47
  • 358
  • 399
  • 2
    One case where it's useful to assign a number to a pointer include operating system kernels and device drivers, where you need to use a specific address to communicate with a device. It's also not uncommon to "hide" numbers in a pointer variable when that's all one has available (perhaps in a pre-existing struct or API). – pburka Sep 29 '13 at 12:11
  • I hope that if any data was assigned to that memory or any kind of access to that memory will throw segmentation fault...am i correct? – Tonmoy Sep 29 '13 at 13:40
  • @Tonmoy: If the memory isn't accessible then yes, you'll get a segfault. But if it *is* accessible (say because it's part of some other data structure) and you write to it, you'll overwrite whatever was there before without any immediate symptoms. – RichieHindle Sep 29 '13 at 13:55
1

That line elfPtr = ((struct Elf *)0x10000); will make the pointer of type *Elf * points to the memory address identified by the hexadecimal number 0x10000 (65536 in decimal)

So whatever there at that memory address, you're assuming that it is of type "Elf"

Rami
  • 7,162
  • 1
  • 22
  • 19
0

With that command you are telling the compiler that the data present at address 0x10000 is an instance of a struct of type "Elf", and assigning a pointer of that type to that address.

Note that you have not instantiated any structure of that type at that address, or even reserved memory for it , so at the very least you will get garbage, if not a segmentation fault, when trying to reference to its members.

You really should avoid using absolute addresses (unless for example low level microcontroller programming), it makes for unportable code, if it even runs.

vinaut
  • 2,416
  • 15
  • 13