Possibly a Pointer Problem in C
I am not sure why the following code fragement is not doing what it is supposed to do. Returning the numbers 0 to 9 in the second loop would be idea. *scp is a pointer to a memory region allocated to the program.
unsigned char* scp = (unsigned char*)(0x8e00开发者_如何学Go0000);
scp_size = 10;
for(i = 0; i < scp_size; i++, scp++) {
*scp = i;
}
}
scp = (unsigned char*)(0x8e000000);
for(i = 0; i < scp_size; i++, scp++) {
printf("Data read[%d]: %d\n", i, *scp);
}
The acual output is however completely different:
[exec] Data read[0]: 3
[exec]
[exec] Data read[1]: 3
[exec]
[exec] Data read[2]: 3
[exec]
[exec] Data read[3]: 3
[exec]
[exec] Data read[4]: 128
[exec]
[exec] Data read[5]: 35
[exec]
[exec] Data read[6]: 32
[exec]
[exec] Data read[7]: 1
[exec]
[exec] Data read[8]: 18
[exec]
[exec] Data read[9]: 146
Anybody an idea if I mixed here something up with the pointer or any other idea what might have gone wrong? Many thanks
The code as you posted it is right. The problem is not here.
There is a problem with the special memory region that you are writing to. Either it is read-only, or can't be written directly, or something in this way. Maybe someone can help you further if you tell us the platform that is running this code.
As @Jari pointed out, it will be cleaner if you used array access.
Your format specification to printf
doesn't match the types you actually pass into it, so all bets are off. scp
is a pointer to unsigned character, but you give printf
a %d
format specifier, which means integer. Since printf
takes varargs, the compiler can't auto-promote *scp
to int. Effectively (on 32-bit integer systems), it's reading your character and three garbage bytes and interpreting that as an integer, then printing that value.
Try printf("Data read[%d]: %d\n", i, static_cast<int>(*scp));
All that being said, you can't just write to arbitrary memory address like that. To allocate memory use:
unsigned char* scp = new unsigned char*[10];
This works:
int main(int argc, char* argv[])
{
unsigned char arr[10];
unsigned char* scp = arr;
int scp_size = 10;
int i = 0;
for(i = 0; i < scp_size; i++, scp++) {
*scp = i;
}
scp = arr;
for(i = 0; i < scp_size; i++, scp++) {
printf("Data read[%d]: %d\n", i, *scp);
}
return 0;
}
Is the memory being changed between the write and the read?
Is there any reason why you are not using array access to the memory are pointed to by scp? I was thinking something like this:
for(i = 0; i < scp_size; i++) {
scp[i] = i;
}
for(i = 0; i < scp_size; i++) {
printf("Data read[%d]: %d\n", i, scp[i]);
}
Probably you are running in user mode, where pointers are virtual addresses. But your 0x8e000000 is a physical address. You can't just "turn off" the MMU without disrupting every other piece of code running on the machine, you need to find your OS's kernel call for creating a virtual mapping to a particular physical address space. On Linux, you could probably mmap /dev/mem
or /dev/kmem` to accomplish this.
The code looks like it should work to me (though I would have used an array). I'd try stepping through it with a debugger and watching what happens to the memory or setting watchpoints.
I suspect that one of two things is happening:
Perhaps the printf in the second loop may be misinterpreting the third parameger (*scp). Remember that printf isn't type-safe. *scp may be being interpreted as an int because you are using the %d format specifier - there doesn't appear to be a format specifier for unsigned char. Try this:
scp = (unsigned char*)(0x8e000000);
for(i = 0; i < scp_size; i++, scp++) {
int val = *scp;
printf("Data read[%d]: %d\n", i, val);
}
Alternatively the contents of the memory block is being changed between your writing to it and reading it. Is it shared memory that is written to by another process/thread/t, or some kind of device-mapped buffer? Can you remove the possibility that another process or device is writing to it?
Possibly the memory area is not writable?
came across below. this should help:-
Explore the memory management capabilities and/or the memory map of your hardware, and/or your OS, and/or your system monitor.
If you can represent a value that is guaranteed to be a specific memory address as constrained by your system, as a C pointer, than you can do what you suggest. You may be forced to do this in assembly, and even then, on many operating systems, you have to build something like a kernel driver in order to allocate anything other than virtual memory.
That said, memory mapped I/O is still quite common. but memory-mapped I/O bound to a specific hardware address space is really not something you can talk about strictly in the context of C. This is a question for comp.arch, or for some forum devoted to your hardware or OS platform.
There are linux kernel drivers that deal with memory-mapped I/O in all kinds of devices, and might not be too hard to analyze. I'd look at some of the ISA drive controllers or old sound cards for likely places to find examples (but I am just guessing).
It's bad practice to do what you are doing with 0x8e00... unless you have a specific reason such as it is memory mapped IO register or something. You need to tell us what in the world you are trying to do first; at first glance this is bad code, you are mixing types, grabbing what looks to be random memory locations, etc.
If I assume the loop variable i is an int, then at every step you are writing an integer (i) starting at 0x8e000000 (which takes up sizeof(int) number of bytes) and incrementing scp by sizeof(unsigned char) number of bytes. Since the size of an int and a char (4 and 1 on most systems) is different, scp++ is not advancing your pointer by the correct number of bytes. So the next time round you do an *scp = i, you are overwriting the previous integer the 3rd byte onwards.
精彩评论