This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

On debug method(How to implement the "TRACE" macro?)

Dear all,my footprint of 51 on my project board is PLCC44,so the ICE can't be used(footprint is DIP40).I have to connect the 51's serial port to PC and dump everthing I need to it.So the program of debug version are full of "printf" statements which are unnecessary on release version.Thus,Can we write a "TRACE" macro to resolve it?MFC implement it for us while Keil C don't.

Parents
  • MFC implement it for us while Keil C don't

    I'll get back to you when I'm done with my port of MFC to the 8051. I still have some issues with the DirectX 9 support for multiprocessor support.

    In the meantime, it's a pretty easy macro to write:

    #if DEBUG
    #define TRACE(args) printf(args)
    #else
    #define TRACE(args)
    #endif

    Define DEBUG, and you get your debug code. Don't define it, and the statements all vanish.

    If I've got a fancy CLI to play with, I like to add a "debug level" to the macro to control verbosity of the output. I assign the debug output to "high", "medium", "low" levels of detail (1, 2, 3). Then, I can use an 'if' statement to compare to a dynamically controlled debug level variable so that I'm not always buried in the maximum spew from the debug code, but can turn it on when I want. A little more macro sleight-of-hand lets you selectively compile out debug levels you don't want in the code.

    Different preprocessors seem to handle the problem of variable arguments differently. That is, if you have

    printf ("%d %d %d\n", d1, d2, d2);

    you may or may not be able to call

    TRACE ("%d %d %d\n", d1, d2, d2);

    since there are four actual arguments to TRACE but only one formal argument declared. Some preprocessors simply make the last argument match all arguments to the macro. If I recall correctly, C99 actually adds support for variadic macro declarations. But I also can sometimes get away with an extra level of parens:

    TRACE (("%d %d %d\n", d1, d2, d2));

    which is a little ugly, but groups all the arguments into one single one for the macro expansion.

Reply
  • MFC implement it for us while Keil C don't

    I'll get back to you when I'm done with my port of MFC to the 8051. I still have some issues with the DirectX 9 support for multiprocessor support.

    In the meantime, it's a pretty easy macro to write:

    #if DEBUG
    #define TRACE(args) printf(args)
    #else
    #define TRACE(args)
    #endif

    Define DEBUG, and you get your debug code. Don't define it, and the statements all vanish.

    If I've got a fancy CLI to play with, I like to add a "debug level" to the macro to control verbosity of the output. I assign the debug output to "high", "medium", "low" levels of detail (1, 2, 3). Then, I can use an 'if' statement to compare to a dynamically controlled debug level variable so that I'm not always buried in the maximum spew from the debug code, but can turn it on when I want. A little more macro sleight-of-hand lets you selectively compile out debug levels you don't want in the code.

    Different preprocessors seem to handle the problem of variable arguments differently. That is, if you have

    printf ("%d %d %d\n", d1, d2, d2);

    you may or may not be able to call

    TRACE ("%d %d %d\n", d1, d2, d2);

    since there are four actual arguments to TRACE but only one formal argument declared. Some preprocessors simply make the last argument match all arguments to the macro. If I recall correctly, C99 actually adds support for variadic macro declarations. But I also can sometimes get away with an extra level of parens:

    TRACE (("%d %d %d\n", d1, d2, d2));

    which is a little ugly, but groups all the arguments into one single one for the macro expansion.

Children
  • The extra level of parenthesis works fine with C51.

  • Many thanks,Davis.You give a very smart way.But the following statements

    typedef unsigned long ULONG;
    ULONG xdata * data pMem = 0;
    TRACE (("Read Value:%lXH\n", *pMem));
    
    cause error.It's error C214: illegal pointer conversion.I don't know why.And,the invoke way "TRACE (("..."));" looks a little strange that anybody else may get confused.Further more,if we have a defined TRACE macro,shall we define _DEBUG or _RELEASE in every source files?

    Do you have an alternative way to implement this macro just like MFC gives us?I have tried to define the TRACE as a function.
    //debug.h
    #ifndef __DEBUG_H__
    #define __DEBUG_H__
    
    #ifdef _RELEASE
    //release mode
    #define TRACE(const char * format, ...)//cause error
    #else
    //debug mode
    #include <stdio.h>
    void TRACE (const char * format, ...);
    #endif //_RELEASE
    
    #endif //__DEBUG_H__
    
    //debug.c
    #include <stdio.h>
    #include <stdarg.h>
    
    void TRACE (const char * format, ...)
    {
    	va_list ap;
    	va_start (ap, format);
    	printf (format, ap)
    	va_end (ap);
    }
    
    The TRACE function of the debug mode is successfully compiled,but the TRACE macro of the release mode isn't.I have searched the MFC source code and wanted to look for the definition of the TRACE macro,but I cound't find it.

    I know MFC needs PC and I don't want to port MFC to keil.For keil don't define some convenient macros such as HIBYTE,LOBYTE etc,we must define it ourselves.A direct way is to steal the codes from the windows SDK or MFC.Now I need a TRACE macro to simplify the development and I'm not skillful enough.Please help me.Thank you very much.

  • That error C214 you got almost certainly has nothing to do with the TRACE macro as such, but with the argument list you passed it.

    #defining DEBUG or RELEASE is supposed to be done by the project / makefile, so you can decide at compile time, outside the code, which modules to compile with the debug printouts active.

    Seriously, though: if you need to look into Microsoft SDKs to rip off a HIBYTE() macro instead of rolling your own, that's a strong sign you're in well over your head already. You'll have to brush up your knowledge of the C programming language considerably before you go on working on embedded software, I think.

  • "macros such as HIBYTE,LOBYTE etc,we must define it ourselves.A direct way is to steal the codes from the windows SDK or MFC"

    Be very careful!

    Not only are you dealing with a different Compiler, but also a completely different target.

    You can't just steal them - you will need to read them carefully & fully understand them to be able to decide if they will give the right resuls with Keil C51, or what modifications are required!

  • You need something like this:

    ifdef DEBUG
    //Debug mode - TRACE causes printf output
    #include <stdio.h>
    #define TRACE(params) printf params;
    #else
    //Release mode - TRACE expands to nothing!
    #define TRACE(params)
    #endif // DEBUG
    and use it like this:
    void some_func( char x )
    {
       TRACE( ("Entered some_func( %bX )", x) )
       :
       :
    }
    Note the use of two sets of parentheses - the outer set is part of the macro "call", and the inner set is taken as part of the parameter passed to the macro - and hence appears in (or disappears with) the macro expansion.