cross-posted from: https://lemmy.ml/post/21033409
In the book authored by K.N.King, there’s this example:
viewmemory.c
/* Allows the user to view regions of computer memory */ #include <stdio.h> #include <ctype.h> typedef unsigned char BYTE; int main(void) { unsigned int addr; int i, n; BYTE *ptr; printf("Address of main function: %x\n", (unsigned int) main); printf("Address of addr variable: %x\n", (unsigned int) &addr); printf("\nEnter a (hex) address: "); scanf("%x", &addr); printf("Enter number of bytes to view: "); scanf("%d", &n); printf("\n"); printf(" Address Bytes Characters\n"); printf(" ------- ------------------------------- ----------\n"); ptr = (BYTE *) addr; for (; n > 0; n -= 10) { printf("%8X ", (unsigned int) ptr); for (i = 0; i < 10 && i < n; i++) printf("%.2X ", *(ptr + i)); for (; i < 10; i++) printf(" "); printf(" "); for (i = 0; i < 10 && i < n; i++) { BYTE ch = *(ptr + i); if (!isprint(ch)) ch = '.'; printf("%c", ch); } printf("\n"); ptr += 10; } return 0; }
For some reason, when I try to enter
addr
variable address as the parameter, it has a segmentation fault error. However, in the book’s example and the screenshot from this site in Hangul, there’s no such error?When I try using
gdb
to check the issue, here’s what I get:gdb
$ gdb ./a.out --silent Reading symbols from ./a.out... (gdb) run Starting program: /home/<username>/Desktop/c-programming-a-modern-approach/low-level-programming/a.out [Thread debugging using libthread_db enabled] Using host libthread_db library "/gnu/store/zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39/lib/libthread_db.so.1". Address of main function: 401166 Address of addr variable: ffffd678 Enter a (hex) address: ffffd678 Enter number of bytes to view: 64 Address Bytes Characters ------- ------------------------------- ---------- Program received signal SIGSEGV, Segmentation fault. 0x000000000040123a in main () at viewmemory.c:31 warning: Source file is more recent than executable. 31 printf ("%.2X ", *(ptr + i)); (gdb)
What is going on? By the way, I am using Guix, if that matters in any way. Here’s the output for
ldd
:ldd
$ ldd ./a.out linux-vdso.so.1 (0x00007ffecdda9000) libgcc_s.so.1 => /gnu/store/w0i4fd8ivrpwz91a0wjwz5l0b2ralj16-gcc-11.4.0-lib/lib/libgcc_s.so.1 (0x00007fcd2627a000) libc.so.6 => /gnu/store/zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39/lib/libc.so.6 (0x00007fcd2609c000)
Looks like this program is really old. It appears to be designed for a 32-bit system, the way it casts between
unsigned int
and pointers.unsigned int
is probably 32-bit even on your 64-bit system, so you’re only printing half the pointer with theprintf
, and only scanning half the pointer with thescanf
. The correct data type to be using for this isuintptr_t
, which is the same asuint32_t
on a 32-bit system, and the same asuint64_t
on a 64-bit system.Try changing the type of
addr
touintptr_t
, and change lines 14-17 to this:printf("Address of main function: %p\n", (void *) &main); printf("Address of addr variable: %p\n", (void *) &addr); printf("\nEnter a (hex) address: "); scanf("%p", &addr);
You may have to include
<stdint.h>
. These changes should make the code portable to any 32-bit or 64-bit architecture.This worked for me - I think
%p
fixed the issue of incorrect representation, as well as input. I also triedunsigned long int
, which works in place ofuintptr_t
, but I’m assuming that it isn’t portable.Resolved code snippet
/* Allows the user to view regions of computer memory */ #include <ctype.h> #include <stdint.h> #include <stdio.h> typedef unsigned char BYTE; int main (void) { uintptr_t addr; int i, n; BYTE *ptr; printf ("Address of main function: %p\n", (void *) &main); printf ("Address of addr variable: %p\n", (void *) &addr); printf ("\nEnter a (hex) address: "); scanf ("%p", &addr); printf ("Enter number of bytes to view: "); scanf ("%d", &n); printf ("\n"); printf (" Address Bytes Characters\n"); printf (" ------- ------------------------------- ----------\n"); ptr = (BYTE *) addr; for (; n > 0; n -= 10) { printf ("%8X ", (uintptr_t) ptr); for (i = 0; i < 10 && i < n; i++) printf ("%.2X ", *(ptr + i)); for (; i < 10; i++) printf (" "); printf (" "); for (i = 0; i < 10 && i < n; i++) { BYTE ch = *(ptr + i); if (!isprint (ch)) ch = '.'; printf ("%c", ch); } printf ("\n"); ptr += 10; } return 0; }