Can we print the data just by using bare address in C? - c

I was wondering whether we can print data at a particular location just by using the bare address of that location in C language.
for eg, Here is the code I used :
#include<stdio.h>
int main(int argc, char** argv) {
int num = 10;
int *ptr;
ptr = &num;
//To output the address of the "num" variable
printf("Address: %p\n", ptr);
//Address is 0x7fff47808f50...
//Using that address to print the data at variable "num"
printf("Data: %d\n", *(0x7fff47808f50));
return 0;
}
But it is showing error. Maybe I've used the wrong syntax or maybe this is not the way to do it.Anyhow, please tell me the right way to do it.

You could (thought shouldn't) cast the integer to a pointer like so: (void *) 0x7fff47808f50.
The conversion has implementation-defined and undefined aspects, however, meaning your mileage will vary. The value will obviously change from compiler to compiler, perhaps even for different compilations, and byte order probably won't be the same as the way we conventionally write numbers, meaning you'll probably have to tinker quite a bit to get this working.
This is nonetheless demonstrable in practice, when that implementation-defined behaviour allows us to reproduce that behaviour, the following will be compliant:
unsigned long long ptr_as_integer = (unsigned long long) "hello world";
printf("%s", (void *) ptr_as_integer);
int value = 42;
unsigned long long value_ptr_as_integer = (unsigned long long) &value;
printf("%d", * (int *) value_ptr_as_integer);
There's also the uintptr_t type, which is designed specifically for this, but that's optional and so not guaranteed to exist...
It's fine to be curious; that's how we learn best... but please don't use this in practice! How often have you been taught not to use magic numbers?

You can use a char * to alias a pointer of another type to read individual bytes:
int i;
char *p = (char *)ptr;
for (i=0; i<sizeof(*ptr); i++) {
printf("p[%d]=%02hhx", i, p[i]);
}

Modify your code
#include<stdio.h>
int main(int argc, char** argv) {
int num = 10;
int *ptr;
ptr = &num;
//To output the address of the "num" variable
printf("Address: %p\n", ptr);
//Address is 0x7fff47808f50...
//Using that address to print the data at variable "num"
printf("Data: %d\n", *ptr);
return 0;
}
the answer to you question is YES.
BUT:
You must be 100% sure what address to use. For example in any kind of firmware you always have addresses of registers defined in manuals as regular numbers. and we use them like this
#define MY_REG_ADDR 0x12345ABC
int a = *((int*)(MY_REG_ADDR))
Modern OSes do address randomization so executable's virtual address sapce is changed every time you run your application so you CANNOT just use hardcoded address.
here is the output after i ran the app 4 times (modified code)
Address: 0x7ffc279af5ac
Data: 10
Address: 0x7ffc2d78021c
Data: 10
Address: 0x7fffb36ae32c
Data: 10
Address: 0x7ffca2c2a9ec
Data: 10
Every tine you change your code memory layout might change so variabl's address might also change

Related

assign address of char pointer to int

I have a function that gets an integer as a parameter. I want to send a char array's address to it, then print the array from its address. I mean:
void printSomeThing(int x){
printf("Variable is: %s\n", /*What to type here?*/);
//I want this printf to write "file.txt"
}
....
int main(){
char filename[10] = "file.txt";
char *filePointer = filename; //So it points to filename[0]'s address.
int x = /*How to convert the address of the pointer (or the char array) to an integer?*/
printSomeThing(x);
}
So, I want to send the char array's address to the function and print that address's value.
NOTE: I can't change the printSomeThing parameter. It has to be an int.
The proper way to convert between pointer addresses and integers is to use the uintptr_t integer type. This is a type guaranteed to be large enough to hold an address (unlike int). This code is fairly safe and portable:
#include <stdio.h>
void printSomeThing(uintptr_t x){
printf("Variable is: %s\n", (char*)x);
}
int main(){
char filename[10] = "file.txt";
char *filePointer = filename; //So it points to filename[0]'s address.
uintptr_t x = (uintptr_t)filePointer;
printSomeThing(x);
}
If sizeof(int) != sizeof(char*), then what you're trying to do is not possible, in general.
However, there is a way to still make this work. Before I tell you how to achieve this, let me reiterate what others have said: you should not use an int as a pointer. This is not a good idea. What I am going to demonstrate is just that: a demonstration. Just because it can be done doesn't mean it should be done.
One way to make this work is to map memory at an address smaller than 1 << (sizeof(int) * 8). Then, copy the string you want to that memory location. Now, you can pass this pointer to your printSomething(int) function.
There is one problem with this solution: it's not portable, so it doesn't always work. I couldn't get it to work with clang on macOS, but it does work here. Here is the code I used.
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
void printSomething(int x){
printf("Variable is: %s\n", (char*) x);
}
int main(){
char filename[10] = "file.txt";
char *allocd = mmap((void*) 0x10000, sizeof(filename)+1,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
strcpy(allocd, filename);
printSomething((int) allocd);
}
Another solution that should probably only be used as a demonstration is one where you ask gcc to define a section at a low memory address. This answer does something along those lines. This is probably not portable either.
The best way I could think to do this given that you dont want to just pass a pointer to the array - would be to cast it to an unsigned long in order to give it to the function.
However your compiler might complain that you are passing an integer value to a string pattern in printf but that is by virtue of the design you are using.
If you dont need to use printSomeThing(int i) then just pass the char* itself or use a void* if you need other things passed through and use some sort of flag to tell the function what type you passed

Is this way of using indirect addressing correct?

I'm watching a college lecture about direct and indirect reference.
The professor just said that you can access a determined address by putting * and the address ahead of it. In the example he gave printf("%d", *7); will print the value in the memory address 7. That doesn't happen to be true, at least it didn't work at all for me.
For example, I had a variable num at address 0x28cc48 or 2673736. When I do *b = &num, I can access the variable's value with printf("%d", *b);, but If I try printf("%d", *2673736); or printf("%d", *0x28cc48); that won't work.
Here's the lecture, for those who want to check it: https://youtu.be/Rxvv9krECNw?t=8m45s
I don't know, I think his explanation is broken, but it may be that I'm missing the point, so I'm willing to know a bit more about this from the more experienced ones.
When you are using *7 in your code, the compiler has no real idea of what you are trying to de-reference. If you, on the other hand, tell it *(int*)7, it knows it has to de-reference it as an int.
In general, location 7 in memory would not even be accessible and it is a bad practice to hardcode addresses into your code. In the case of microcontrollers or embedded systems however, it might be used however.
When you say *b = &num, it matters whether you are doing it at declaration time, or after it, since int *b = &num; is very different from int *b; *b = &num;. In fact, the first usage is the same as int *b; b = &num;.
Here's some code to clarify the scenario that you are probably trying to get to:
#include <stdio.h>
int main() {
int num = 5;
int *a = &num;
int *b; b = &num;
printf("num = %d, &num = 0x%x", num, &num);
printf("a = 0x%x, *a = %d", a, *a);
printf("b = 0x%x, *b = %d", b, *b);
printf("*0xAAAAAAAA = %d", *(int*)0xAAAAAAAA); // Note: Replace 0xAAAAAAAA with whatever value you get for num from previous executions of this program
}
PS: It might be worth to take a look at Stanford's excellent resource on Pointers and Memory. http://cslibrary.stanford.edu/102/PointersAndMemory.pdf
If you want to access memory at a fixed address (common for example when accessing registers on a microcontroller), use an expression like this:
int tmp = *((int*)0x01234567);
Since a constant number does not really have a type, in order to use a constant number as an address, you have to tell the compiler the type of address by using a cast.
So if you have a particular memory address in low memory with certain types of constants you would need to specify the memory address with the cast in order for the compiler to know what type is the data at that memory location.
For instance you may have a set of unsigned shorts that are counters starting at a memory location of 8 with device names starting at a location of 0x700 so you could access them like so:
unsigned short iVal = *((unsigned short *) 8); // get unsigned short value at address 8
unsigned short jVal = *((unsigned short *) 10); // get unsigned short value at address 10
char *iName = (char *) 0x700; // get the address 0x700 into a char pointer
char *jName = (char *) 0x710; // get the address of 0x710 into a char pointer

Casting char pointer to int pointer - buffer error 10

In this answer, the author discussed how it was possible to cast pointers in C. I wanted to try this out and constructed this code:
#include <stdio.h>
int main(void) {
char *c;
*c = 10;
int i = *(int*)(c);
printf("%d", i);
return 1;
}
This compiles (with a warning) and when I execute the binary it just outputs bus error: 10. I understand that a char is a smaller size than an int. I also understand from this post that I should expect this error. But I'd really appreciate if someone could clarify on what is going on here. In addition, I'd like to know if there is a correct way to cast the pointers and dereference the int pointer to get 10 (in this example). Thanks!
EDIT: To clarify my intent, if you are worried, I'm just trying to come up with a "working" example of pointer casting. This is just to show that this is allowed and might work in C.
c is uninitialized when you dereference it. That's undefined behaviour.
Likewise, even if c were initialized, your typecast of it to int * and then a dereference would get some number of extra bytes from memory, which is also undefined behaviour.
A working (safe) example that illustrates what you're trying:
int main(void)
{
int i = 10;
int *p = &i;
char c = *(char *)p;
printf("%d\n", c);
return 0;
}
This program will print 10 on a little-endian machine and 0 on a big-endian machine.
These lines of code are problematic. You are writing through a pointer that is uninitialized.
char *c;
*c = 10;
Change to something like this:
char * c = malloc (sizeof (char));
Then, the following line is invalid logic, and the compiler should at least warn you about this:
int i = *(int*)(c);
You are reading an int (probably 4 or 8 bytes) from a pointer that only has one byte of storage (sizeof (char)). You can't read an int worth of bytes from a char memory slot.
First of all your program has undefined behaviour because pointer c was not initialized.
As for the question then you may write simply
int i = *c;
printf("%d", i);
Integral types with rankes less than the rank of type int are promoted to type int in expressions.
I understand that a char is a smaller size than an int. I also understand from this post that I should expect this error. But I'd really appreciate if someone could clarify on what is going on here
Some architectures like SPARC and some MIPS requires strict alignment. Thus if you want to read or write for example a word, it has to be aligned on 4 bytes, e.g. its address is multiple of 4 or the CPU will raise an exception. Other architectures like x86 can handle unaligned access, but with performance cost.
Let's take your code, find all places where things go boom as well as the reason why, and do the minimum to fix them:
#include <stdio.h>
int main(void) {
char *c;
*c = 10;
The preceding line is Undefined Behavior (UB), because c does not point to at least one char-object. So, insert these two lines directly before:
char x;
c = &x;
Lets move on after that fix:
int i = *(int*)(c);
Now this line is bad too.
Let's make our life complicated by assuming you didn't mean the more reasonable implicit widening conversion; int i = c;:
If the implementation defines _Alignof(int) != 1, the cast invokes UB because x is potentially mis-aligned.
If the implementation defines sizeof(int) != 1, the dereferencing invokes UB, because we refer to memory which is not there.
Let's fix both possible issues by changing the lines defining x and assigning its address to c to this:
_Alignas(in) char x[sizeof(int)];
c = x;
Now, reading the dereferenced pointer causes UB, because we treat some memory as if it stored an object of type int, which is not true unless we copied one there from a valid int variable - treating both as buffers of characters - or we last stored an int there.
So, add a store before the read:
*(int*)c = 0;
Moving on...
printf("%d", i);
return 1;
}
To recap, the changed program:
#include <stdio.h>
int main(void) {
char *c;
_Alignas(in) char x[sizeof(int)];
c = x;
*c = 10;
*(int*)c = 0;
int i = *(int*)(c);
printf("%d", i);
return 1;
}
(Used the C11 standard for my fixes.)

C: Access 'char' in specific memory location?

I was interested in accessing portions of memory I had allocated to get a better understanding of things, lets say I allocate 10 bytes with malloc and printf("%p", &foo) returns 0xff0a, would I be able to allocate 0xff0a->0xff1a (my hexadecimal math is bad at the moment) and access any one of those individual bytes?
I think I recall being used the keyword volatile along with a memory address for this, I am not sure what that code was able to do though..
I guess what I mean is how do I access a random byte in memory, cast as a char or integer that I can store in a pointer for accessing later on.
I'll assume you want to access a single byte from a multi-byte type such as an int or a short. The common idiom is to cast the address to a char* and deference that like so:
#include <stdio.h>
int main(void)
{
int foo = 0xDEADBEEF;
int i;
for (i = 0; i < 4; i++) {
printf("byte %d of foo is x%02X\n", i, *((unsigned char*)&foo + i));
}
return 0;
}
Output
$ ./a.out
byte 0 of foo is xEF
byte 1 of foo is xBE
byte 2 of foo is xAD
byte 3 of foo is xDE
Note The reason it looks backwards is due to x86 being little endian
printf("%p", &foo) prints the address of the pointer variable foo, not the address contained in foo (which is the one that came from malloc). You actually want:
printf("%p", (void *)foo);
If you wish to access the 10 bytes in memory pointed to by foo, you can simply use:
char *p = foo;
and then access p[0] through p[9].
If you allocate 10 bytes from 0xff0a, the address range is: 0xff0a to 0xFF14.
volatile forces the compiler to grab the stored value at that location every time. This has uses in hardware programming and multi-threaded applications.
This example stores the address of the int x into the pointer p:
int x = 5;
int * p = &x; //assign address of (operator &) x into a pointer
printf("%d\n", *p); // will display 5
You may want to use a union in order to always apply the same bunch of code to loop over the bytes area of your variable. The member 'byte' will always point to the same address as the others. You can include it into a struct in order to keep the size along with the union. A the end, you just call a function to print out or check the content of a bunch of memory...
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>
union byteMap {
char* addressString;
void* addressInt;
unsigned char* byte;
};
struct structByteMap {
size_t size;
union byteMap map;
};
int main (int argc, char* argv[]) {
struct structByteMap map;
if (argc > 1) {
int temp = strtoimax(argv[1], NULL, 10);
map.map.addressInt = &temp;
map.size = sizeof(int);
} else {
map.map.addressString = "HELLO, YES HELLO";
map.size = strlen(map.map.addressString);
}
for (int i = 0; i < map.size; i++) {
printf("byte %d of param is x%02X\n", i, *(map.map.byte + i));
}
}

How to cast a void* to int in 64-bit platforms, using C?

I am a linguist in charge of a C program, so please excuse me if the answer is obvious. I have the following code:
typedef struct array_s {
(...)
void **value;
} array_t;
typedef array_t *array_pt;
array_pt array_new (int size) {
(...)
array->value = (void **)malloc(size*sizeof(void *));
}
void* array_get (array_pt arr, int i) {
return arr->value[i];
}
int main () {
int a = 1234;
int *ptr = &a;
array_pt array = array_new(1);
array_add(array, ptr);
printf("%i\n", (int)array_get(array, 0));
}
It is supposed to provide me with a multi-purpose array (for storing int and char*, if I understood I can only use void), and I guess there are no problems of allocating/freeing. However, I cannot get to cast it into anything useful (i.e., get back the "original" int/char*), and for what I understood it could be because I am in a 64-bit system and the size of a pointer to void is different from the size of a pointer to int/char* (the program is supposed to be used in both 64 and 32 bit systems). I tried using intptr_t and other alternatives, to no luck.
How can I be sure that the code will accept any data type and work on both 32 and 64 bit systems? Thank you.
EDIT:
Sorry for not adding array_add, here it is:
unsigned int array_add (array_pt array, void *ptr) {
(...) // get the next index
// allocate if needed
array->value = (void **)realloc(array->value, array->size*sizeof(void *));
array->value[index] = p;
}
You need to dereference your pointer:
int* temp = array_get(array, 0);
printf("%i\n", *temp);
However, I strongly recommend avoiding this type of approach. You're basically giving away the small amount of help the compiler in C will normally provide - purposefully trying to make non-typesafe arrays.
You need to decide what is it you are trying to do in this case.
(1) If you want to use your void * array to store int values (actual int forcefully converted to void *), then you should add these int values to the array as follows
int a = 1234;
array_pt array = array_new(1);
array_add(array, (void *) a);
and then get them back from array as follows
int a = (int) array_get(array, 0);
printf ("%d\n", a);
or simply
printf ("%d\n", (int) array_get(array, 0)));
That last part is exactly what you did, but you got the first part wrong.
This is a cast-based approach, which is ugly in many ways, but it has certain practical value, and it will work assuming void * is large enough to hold an int. This is the approach that might depend on the properties of 32- and 64-bit systems.
(2) If you want to use your void * array to store int * values (pointers to int), then you should add these int values to the array as follows
int a = 1234;
array_pt array = array_new(1);
array_add(array, &a);
and then get them back from array as follows
int *pa = array_get(array, 0);
printf ("%d\n", *pa);
or simply
printf ("%d\n", *(int *) array_get(array, 0));
This approach is perfectly safe from any portability problems. It has no 32- or 64-bit issues. A void * pointer is guaranteed to safely hold a int * pointer or any other data pointer.
If that was your intent, then you got the first part right and the last part wrong.
Either this or that. You code appears to be a strange mix of the two, which is why it doesn't work, and which is why it is impossible to figure out from your original message which approach you were trying to use.
intmax_t should be an integer type that is 32 bits on 32bits compilers and 64bits on 64bit compilers. You could use %j in your printf statement to print intmax_t. The size of pointers on one system is always the same - independently of them pointing to int, char or void.
printf("%j\n", (intmax_t)array_get(array, 0));

Resources