tags:

views:

267

answers:

10

Hi all,

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*)(0x8e000000);
 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

+1  A: 

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]); 
}  
Jari
The reason for that is, that the memory location is fixed at 0x8e000000 where I want to write too. Else this makes of course sense Jari ;)
Rob
Jari's example does in fact operate on 0x8e000000 if that is where scp is pointing.
I still don't see the difference of using *scp and scp[i], although that might not be the problem in your code.
Jari
There is no difference, for built-in types.
Ben Voigt
+2  A: 

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?

Patrick
A: 

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.

sauparna
If this was the problem, shouldn't the behaviour be different? Either all printed values should be 0 (on a big endian system) or the values should be be printed as 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, as intended (on a little endian system).
Alderath
@sauparna I don't think that your answer is correct. The OP isn't writing ints to the memory block. To do that would require that scp be of type int*. The line '*scp = i;' converts the integer value of i to an unsigned char and writes it (as an unsigned char) to the address pointed to by scp. What you are saying would require something like '*(int*)scp = i;'.
Andy Johnson
No, `*scp = i` will truncate the integer value to a char and only write one byte.
Mike Seymour
Well, I probably added more confusion with my comment. The OP should skip over this section and get on with the other answers. And thanks everybody for explaining it. So am I right if I say that when we have a similar situation when we assign a double to an int and the double gets truncated to the shorter value?
sauparna
@sauparna Correct
Andy Johnson
+6  A: 

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.

asr
A: 

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.

Nathon
A: 

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?

Andy Johnson
Shouldn't the int val = *scp; declaration be outside the for loop?
Tangrs
@Tangrs No, for each interation my suggestion is to _explicitly_ convert *scp to an int, and then print it, rather than assuming that printf will do the conversion correctly.
Andy Johnson
A: 

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).

Kedar
+1  A: 

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.

Ben Voigt
+3  A: 

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];

Mark B
A: 

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.