Ex19 someone put my out my misery

Hi all,

As far as I can see, I’ve written the code correctly. But when I try to define NDEBUG in the c file, it makes no difference. Also it makes no difference adding -DNDEBUG to the Makefile flags. I’m using cygwin on windows if that makes any difference.

EDIT: Also, maybe this is explained later, but how does ‘errror:’ work? The syntax isn’t explained.

    #define NDEBUG

   #include "dbg.h"
   #include <stdlib.h>
   #include <stdio.h>
   
   void test_debug()
   {
       // Notice you don't need the \n
       debug("I have brown hair");
   
       // Passing arguments like printf
       debug("I am %d years old.", 37);
   }
   
   void test_log_err()
   {
       log_err("I believe everything is broken");
       log_err("There is %d problems in %s.", 0, "space");
   }
   
   void test_log_warn()
   {
       log_warn("You can safely ignore this");
       log_warn("Maybe consider looking at: %s.", "/etc/passwd");
   }
   
   void test_log_info()
   {
   	log_info("Well, I did something mundane.");
   	log_info("It happened %f times today.", 1.3f);
   }
   
   int test_check(char *file_name)
   {
   	FILE *input = NULL;
   	char *block = NULL;
   
       block = malloc(100);
       check_mem(block);
   
   	input = fopen(file_name, "r");
   	check(input, "Failed to open %s.", file_name);
   
   	free(block);
   	fclose(input);
   	return 0;
   
   error:
   	if (block) free(block);
   	if (input) fclose(input);
   	return -1;
   }
   
   int test_sentinel(int code)
   {
   	char *temp = malloc(100);
       check_mem(temp);
   
       switch(code) {
       	case 1:
	       	log_info("It worked!");
	       	break;
	       default:
	       	sentinel("I shouldn't run.");
   	}
       
       free(temp);
       return 0;
   
   error:
if (temp)
	free(temp);
return -1;
   }

   int test_check_mem()
   {
   	char *test = NULL;
   	check_mem(test);
   
   	free(test);
   	return 1;
   
   error:
       return -1;
   }
   
   int test_check_debug()
   {
   	int i = 0;
   	check_debug(i != 0, "Ooops, I was 0.");
   
   	return 0;
   error:
       return -1;
   }
   
   int main(int argc, char *argv[])
   {
   	check(argc == 2, "Need an argument.");
   
   	test_debug();
   	test_log_err();
   	test_log_warn();
   	test_log_info();
   
   	check(test_check("ex20.c") == 0, "failed with ex20.c");
   	check(test_check(argv[1]) == -1, "failed with argv");
   	check(test_sentinel(1) == 0, "test sentinel failed.");
       check(test_sentinel(100) == -1, "test sentinel failed.");
       check(test_check_mem() == -1, "test_check_mem failed.");
       check(test_check_debug() == -1, "test_check_debug failed.");

       return 0;

   error:
       return 1;
   }

Here’s the debugger header:

#ifndef __dbg_h__
#define __dbg_h__
#include <stdio.h>
#include <errno.h>
#include <string.h>

#ifdef NDEBUG
#define debug(M, ...)
#else
#define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\
    __FILE__, __LINE__, ##__VA_ARGS__)
#endif

#define clean_errno() (errno == 0 ? "None" : strerror(errno))

#define log_err(M, ...) fprintf(stderr, \
    "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\
    clean_errno(), ##__VA_ARGS__)

#define log_warn(M, ...) fprintf(stderr, \
    "[WARN] (%s:%d: errno: %s) " M "\n",\
    __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)

#define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\
    __FILE__, __LINE__, ##__VA_ARGS__)

#define check(A,  M, ...) if(!(A)) {\
    log_err(M, ##__VA_ARGS__); errno=0; goto error; }

#define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\
    errno=0; goto error; }

#define check_mem(A) check((A), "out of memory.")
#define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\
    errno=0; goto error; }
#endif

Uhhh, my brain is super crusty on this code but I don’t see anything wrong here. Are you thinking that defining NDEBUG will remove all output? It really only removes the debug() lines but leaves log_error and check() becuse those are important to always have.

The error: comes into use with the check() and sentinel() macros. See this part:

errno=0; goto error; }

At the end of those. That goto error`` makes the code jump to your error:``` label, which is also a goto. As in “Go To The Error Store”.

Hi Zed,

Ugh, you know what? That’s it, I was expecing it all to dissapear, I misread the ‘endif’ statement. Now I feel rather silly!

Ahh, so error is a ‘lable’, that something I’d just never come across before. I need to read up more about ‘goto’ clearly.

1 Like
A free service run by Zed A. Shaw for learncodethehardway.org.