Log macros
Learning goals
You will learn the following concepts/skills:
- C preprocessor − how to use several of the most commonly used directives
- #define symbols – not just for defining constants
- #define macros – like functions but with special capabilities
#include
guards – enable more versatile use of header (.h) files.
Overview
For this part, you will create a reusable library for debugging any C project.
When you are done, you will use
log_int(…)
to print an int
variable,
log_float(…)
to print a float
variable,
log_str(…)
to print a str
variable,
log_char(…)
to print a char
variable,
log_addr(…)
to print any address variable (e.g., char*
, int*
, etc.),
log_bool(…)
to print a bool
variable,
You will use these similarly to the way some people use
printf(…)
, but these macros will generate code that
prints the variable name (or expression) as well as the value. For example,
invoking log_int(3 + 4)
will generate
the C code
printf("%s == %d\n", "3 + 4", 7)
, which will print
3 + 4 == 7
.
For this part, you will create a reusable library for debugging any C project. In the process, you will learn about the C preprocessor.
Instructions
Get the starter code.
you@ecegrid-thin1 ~
$
cd 264
you@ecegrid-thin1 ~/264
$
264get hw06
you@ecegrid-thin1 ~/264
$
cd hw06
you@ecegrid-thin1 ~/264/hw06
$
Create log_macros.h
you@ecegrid-thin1 ~/264/hw06
$
vim log_macros.h
Create a new file called log_macros.h and add an include guard to your log_macros.h.
you@ecegrid-thin1 ~/264/hw06
$
gcc test_log_macros.c -o test_log_macros
you@ecegrid-thin1 ~/264/hw06
$
./test_log_macros
you@ecegrid-thin1 ~/264/hw06
$
Compile and run test_log_macros.c.
you@ecegrid-thin1 ~/264/hw06
$
gcc test_log_macros.c test_log_macros
you@ecegrid-thin1 ~/264/hw06
$
./test_log_macros
You should see output for every test. (This is abbreviated.)
So far, all of the output you see is generated by simple printf(…)
statements. As you implement each of the macros for this assignment, you will be creating a test
below each of those. When you are done, running should display two copies of each test.
Enable tests for log_int(…)
and then implement it.
The log_int(…)
function-like macro will print an integer value,
along with the text of argument to log_int(…)
.
Open both test_log_macros.c and log_macros.h in tabs.
you@ecegrid-thin1 ~/264/hw06
$
vim test_log_macros.c log_macros.h
Uncomment the tests for log_int(…)
in log_macros.h.
Switch to the log_macros.h tab. (Press «Tab» or use your mouse.)
Create a #define
macro for log_int(…)
in log_macros.h.
This should be only one line of code.
Compile and run test_log_macros.c.
you@ecegrid-thin1 ~/264/hw06
$
gcc test_log_macros.c -o test_log_macros
you@ecegrid-thin1 ~/264/hw06
$
./test_log_macros
This time, the tests for log_int(…)
should each appear twice
(i.e., one for the simple printf(…)
statement and one for the
real test). Verify that the output matches exactly. The rest of the tests will all appear
only once each.
Enable tests for log_char(…)
, implement it, and test.
Follow the same procedure you used for log_int(…)
. The specification
for log_char(…)
is in the Requirements table. Submit.
Enable tests for log_str(…)
, implement it, and test.
Follow the same procedure you used for log_int(…)
. The specification
for log_str(…)
is in the Requirements table. Submit.
Enable tests for log_addr(…)
, implement it, and test.
Follow the same procedure you used for log_int(…)
. The specification
for log_addr(…)
is in the Requirements table. Submit.
Enable tests for log_float(…)
, implement it, and test.
Follow the same procedure you used for log_int(…)
. The specification
for log_float(…)
is in the Requirements table. Submit.
Enable tests for log_bool(…)
, implement it, and test.
Follow the same procedure you used for log_int(…)
. The specification
for log_bool(…)
is in the Requirements table. Submit.
Test that the complete output matches expected.txt.
First, just compile and run normally, so you can inspect visually.
you@ecegrid-thin1 ~/264/hw06
$
gcc test_log_macros.c -o test_log_macros
you@ecegrid-thin1 ~/264/hw06
$
./test_log_macros
Compare the output of test_log_macros with expected.txt.
you@ecegrid-thin1 ~/264/hw06
$
diff expected.txt <(./test_log_macros)
How much work is this?
Requirements
- Your submission must contain each of the following files, as specified:
file contents log_macros.h macros log int(n)
-
log_int(var_name)
⇔printf("var_name == printf_code\n", var_name)
- Ex:
log_int(3 + 3)
should be expanded by the preprocessor into code that displays this:3 + 3 == 6
log str(s)
-
log_str(var_name)
⇔printf("var_name == printf_code\n", var_name)
- Ex:
char* s = "abc";log_str(s)
should be expanded by the preprocessor into code that displays this:s == "abc"
- Ex:
log_str("abc")
should be expanded by the preprocessor into code that displays this:"abc" == "abc"
log float(n)
-
log_float(var_name)
⇔printf("var_name == printf_code\n", var_name)
log char(ch)
-
log_char(var_name)
⇔printf("var_name == printf_code\n", var_name)
log bool(condition)
-
log_bool(condition)
prints condition == false if condition is false, or condition == true otherwise.
log addr(addr)
-
log_addr(var_name)
⇔printf("var_name == printf_code\n", var_name)
- Examples:
int n = 5; log_addr(&n)
// should print something like&n == 0x7fff938d
int* a_n = &n; log_addr(a_n)
// should print something likea_n == 0x7fff938d
- ⚠ When passing an address to
printf("… %p …")
, you must typecast it tovoid*
.
test_log_macros.c test code main(▒▒▒)
- Follow the instructions to create this file.
-
- Each macro must be exactly one line.
- Do not add any functions.
-
You may hand-copy any code snippets you find in this homework
description into your HW06 submission.
- ⚠ Do not use copy-paste. You learn more from hand-copying unfamiliar syntax. Expect problems if you ignore this.
- Adaptation is strongly recommended. Correct functioning of your code is your responsibility.
- Be sure you understand what you are copying.
- Copying from this page is not necessary. This permission is given as a convenience, since some syntax may be unfamiliar.
-
You may use any of the following:
header functions/symbols allowed in… stdbool.h bool
,true
,false
*.c
,*.h
stdio.h printf
*.c
,*.h
stdlib.h EXIT_SUCCESS
test_log_macros.c
- Submissions must meet the code quality standards and the policies on homework and academic integrity, and follow the general intent of the assignment.
Submit
To submit HW06 from within your hw06 directory,
type
264submit HW06 log_macros.h test_log_macros.c
Pretester
Q&A
Should I have a semicolon at the end of a
No. The person using the macro will normally include the semicolon.#define
macroWhat does
It expands to the text of the expression, instead of its value. This is easiest to see if you test using the 264cpp (or /usr/bin/cpp) command.#x
do in a#define
macroHere is an example, which uses thelog_int(…)
snippet given in the Requirements table.// demonstrate_hash.c #include <stdio.h> #include <stdlib.h> #define log_int(n) printf("%s == %d\n", (#n), (n)) int main(int argc, char* argv[]) { log_int(3 + 3); return EXIT_SUCCESS; }
If we process that with the preprocessor directly (instead of via gcc), we can see what it becomes. Note:264cpp
is just a shortcut for/usr/bin/cpp ▒▒▒ | indent -kr
that also cleans up the output a bit to make it easier to read.you@ecegrid-thin1 ~/HW06 $
/usr/bin/cpp demonstrate_hash.c | indent -kr
… int main(int argc, char* argv[]) { printf("%s == %d\n", ("3 + 3"), (3 + 3)); return 0; }Notice that the second argument toprintf(…)
is a string literal,"3 + 3"
—the text of the argument that was passed tolog_int(…)
. That is different from the third argument, which is the value of that parameter,3 + 3
(= 6).GCC: “error: ‘true’ undeclared” ⋯???
The
GCC: “error: ‘false’ undeclared” ⋯??true
andfalse
constants are defined in a standard header called stdbool.h; you need to include it (i.e.,#include <stdbool.h>
) in any file where you use them (e.g., log_macros.h).true
, andfalse
.
Updates
9/23/2022 |
|