out: Monday, January 11, 2021
due: Wednesday, January 13, 2021 by 10:00 am.
ex02
directory, do
a git pull
to fetch it. Ignore the advanced/
directory. It is
explained at the very end and is completely optional.
We've distributed two files. (1) dumphex.h
declares a single function:
int DumpHex(void* mem_addr, uint32_t num_bytes);(2)
ex02.c
contains a main()
that calls DumpHex()
.
No changes are needed to either file.
No definition of DumpHex()
is provided. Your task is
to implement it. Your code should go in a new file, dumphex.c
.
(Remember to git add
that file so that it makes its way into your
repository.)
DumpHex()
prints (to stdout
) the value of each byte of memory starting
with *mem_addr
and going for num_bytes
bytes.
Each byte's value is printed in hex and consecutive byte values are separated by a space.
The printed string of bytes is preceded by a string indicating what the arguments were.
Your output should mimic this format:
The 4 bytes starting at 0x7fff1081856c are: ff 01 30 4e
DumpHex()
returns 0 for success and a distinct positive value for
each distinct kind of error it detects. (Once again, it is up to you
to identify what the errors are and what codes are returned.)
Your implementation of DumpHex
will need to
do a few things:
void*
in a way
that is correct and doesn't cause any compiler errors or warnings
printf
to print a two digit hex number
printf
to print a pointer value. You'd like to do this in a
portable way. (Pointers are 4 bytes on some (old) systems and 8 bytes on current systems.)
It's easier to debug when you know correct behavior is, so we're telling you. Your code should produce output that is identical to the following, except that there are portions of the output that are printing uninitialized values and the address given has undergone some randomization. That means those things might change from run to run. (Which part is uninitialized? That's something for you to figure out.)
$bash gcc -Wall -std=c17 -g -o ex02 ex02.c dumphex.c
$bash ls
ex02 ex02.c
$bash ./ex02
The 1 bytes starting at 0x7fff3c84a1ff are: 30
The 4 bytes starting at 0x7fff3c84a1f4 are: 01 00 00 00
The 4 bytes starting at 0x7fff3c84a1f8 are: 00 00 80 3f
The 8 bytes starting at 0x7fff3c84a1e8 are: 00 00 00 00 00 00 f0 3f
The 24 bytes starting at 0x7fff3c84a1d0 are: 30 b0 f0 00 01 00 00 00 00 00 80 3f 00 00 00 00 00 00 00 00 00 00 f0 3f
Note that the number of bytes shown on the last line is not the sum of the numbers shown on the previous lines. That's related to what part of the data is uninitialized.
You must not alter main()
or dumphex.h
.
If you notice any style issues with them,
ignore them and focus on getting your added code right.
Your code must:
dumphex.c
gcc -Wall -g -std=c17 -o ex02 ex02.c dumphex.c
/li>
clint
.)
You should tag your submission ex02-final
and submit by pushing to your repository.
The advanced/
subdirectory contains a more sophisticated implementation of the
mainline. It uses an advanced preprocessor feature to make the code easier to create and easier
to maintain. What it does IS NOT A KEY SKILL.
WHEN YOU FINISH the assignment, then IF YOU WANT TO, have a look at the advanced implementation. There are some comments in a README file to help explain it to you. First try to understand the mechanics -- what is happening? Next consider the claims about why this is better that are made in the README and decide if you agree or not. Finally, try to state convincingly why the preprocessor macro TEST(x) could NOT be implemented as a C subroutine.
The advanced/
material is intended to be fun. If you don't find it fun, stop!
P.S. You should feel very free to ask questions of the staff about what is going on, but only if you're actually enjoying this extra material.
The specification of DumpHex
is arguably terrible. It asks you to do two things:
convert the contents of memory to a hex string and print that string. A function should
do only one thing. That way it is more easily used in ways you may not have anticipated when
first writing it.
In Java, we'd fix this by having a routine that returned a string
and that's it,
without printing it.
If the calling routine wanted to print, it could. If it wanted to remember the string in some database,
it could. If it wanted to compare the contents of two different pieces of memory (as strings), it could.
We tend not to do that in C because strings are a real pain, primarily because C doesn't have them (and
doesn't do garbage collection). They're not so much of a pain in C++, though, so we'd maybe do things
differently using that language.