Unexpected output from strtol
c, embedded, embedded-linux
Solution
`strtol()` returns a (signed) `long`. Based on your input, you are trying to parse unsigned 32 bit numbers, so if `long` is 32 bits on your system, `strtol()` is going to go out of range. In this case, it will return `LONG_MAX`, which on your system appears to be `0x7FFFFFFF`.
You should use `strtoul()` instead, and store the result in an `unsigned long`, rather than an `unsigned int` as you are now, since while `long` is guaranteed to be at least 32 bits, `int` is not.
In addition, you really ought to be passing the address of a real pointer as the second argument to `strtol()` and friends, and using it to check for errors. Right now, if either of `argv[1]` or `argv[2]` did not start with a number, you wouldn't be able to distinguish whether the input was bad, or whether the input was a legitimate zero.
Problem
I'm trying to create a small program that takes in a physical memory location and prints the data stored at the location. I'm passing two parameters into the program - the address, and the size (in bytes) of memory I want to print. The issue I'm having is when the address I pass in gets above a certain value the strtol() function passes out a nonsensical value. Code below: ``` #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <asm-generic/fcntl.h> #include <unistd.h> int main(int argc, char** argv) { unsigned int mem_address,mem_size; int loop, i; int *ptr, *mem_address_current; printf("mem_addr: %s\n",argv[1]); printf("mem_size: %s\n",argv[2]); mem_address = strtol(argv[1], NULL, 16); mem_size = strtol(argv[2], NULL, 16); printf("mem_addr: %x\n",mem_address); printf("mem_size: %x\n",mem_size); int mem_dev = open("/dev/mem", O_RDWR); if(mem_dev == -1) { printf("No worky\n"); exit(1); } int alloc_mem_size, page_mask, page_size; void *mem_pointer, *virt_addr; page_size = sysconf(_SC_PAGESIZE); alloc_mem_size = (((mem_size / page_size) + 1) * page_size); page_mask = (page_size - 1); mem_pointer = mmap(NULL, alloc_mem_size, PROT_READ | PROT_WRITE, MAP_SHARED, mem_dev, (mem_address & ~page_mask) ); if(mem_pointer == MAP_FAILED) { printf("no_worky2\n"); exit(1) ; } virt_addr = (mem_pointer + (mem_address & page_mask)); ptr = mem_pointer; loop = (mem_size/16) + 1; for(i = 0;i < loop;i++) { printf("%#x: %08x %08x %08x %08x\n", ptr, *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3)); ptr = ptr + 4; } return 0; } ``` If I run the the following command, I get the expected values. ``` root@p1025:~# ./test_prog_ppc 0100000 16 mem_addr: 0100000 mem_size: 16 mem_addr: 100000 mem_size: 16 0x48001000: 38210020 4e800020 9421ffe0 7c0802a6 0x48001010: 2c050000 bf410008 7c7e1b78 90010024 ``` However, If I change the input address the value changes from what is expected: ``` root@p1025:~# ./test_prog_ppc ffee0000 16 mem_addr: ffee0000 mem_size: 16 mem_addr: 7fffffff mem_size: 16 ``` Any ideas as to why this would happen? Thanks for the help.