How can I debug or do a trace of program with MACRO in C

I have a simple program with MACRO in it as shown:

#include <stdio.h>
#include <stdlib.h>
#define myTest(a) (a[0]) + (a[1])

int main()
{
int x[2] = {23, 45};
myTest((int)x);
return EXIT_SUCCESS;
}

my problem is when I do a debug.
when I put myTest((int)x) in the watch window it shows error"myTest not found ".

To me it is obvious because myTest was replaced by (a[0]) + (a[1], but putting that rValue ( (a[0]) + (a[1]) in the watch window also ends with the same error.

I have to type x[0] + x[1] on the watch window to get a valid answer. But that defeats the purpose of the MACRO. If that is the case then I will just write the actual code directly and forget MACROS.

That should not be the way to debug a program containing MACRO. It should not be hard to follow the variables My question is there any programmer who knows how to do a trace of a program with MACROS, how can I see the value of the variables.
#define is straight text substitution.

What is actually compiled looks like:

1
2
3
4
5
6
int main()
{
    int x[2] = {23, 45};
    ((int)x[0]) + ((int)x[1]) ;
    return EXIT_SUCCESS ;
}


Your compiler probably warns you that this has no effect.
Last edited on
cire

I agree with you 100% that it is just a direct text substitution. But after compiling I am not getting this.

int main()
{
int x[2] = {23, 45};
((int)x[0]) + ((int)x[1]) ;
return EXIT_SUCCESS ;
}


It is still the way I originally wrote it which is. It did compile no error and the result is correct. But I cannot run a trace.

int main()
{
int x[2] = {23, 45};
myTest((int)x);
return EXIT_SUCCESS;
}


Am I missing something in the compiler? are there settings that I should set.
closed account (o1vk4iN6)
That line of code does nothing so even if it was compiled with no optimizations I'd be sceptical about it being in the assembly. So in effect you are getting that, it's just doing something different then what you think it should be.
Last edited on
The line of code is the simplest I could think of and used, so I could ask any programmer if there is a way to debug/trace program with a MACRO. I agree it does nothing but nonetheless it contains MACRO. The simplest it is the easier to figure it out.

The question is, is there a way to trace/ debug/ and see the variables in a program writen with MACRO. Ignore the fact that it is so simple.

"cire" acknowledged that MACRO is just direct text substitution, I assumed that as soon as I complied the program it will do the text substitution and then I can do a trace. But I am not getting the substitution and I am concerned that there is a setting in the compiler that I should modify. I am using a Microsoft Visual 2010.
closed account (o1vk4iN6)
I didn't say it was simple, I said it did nothing, there is a distinct difference.

1
2
3
4
5
int main( int, const char** )
{
    1 + 1;
    return 0;
}


This is the assembly generated using visual C++ 2010:

PUSH EBP ; INT tmp.main(void)
MOV EBP,ESP
SUB ESP,0C0
PUSH EBX
PUSH ESI
PUSH EDI
LEA EDI,[LOCAL.48]
MOV ECX,30
MOV EAX,CCCCCCCC
STOS DWORD PTR ES:[EDI]
XOR EAX,EAX
POP EDI
POP ESI
POP EBX
MOV ESP,EBP
POP EBP
RETN


As you can see no where does it call the add. The only thing it does is initialize the stack for the stack overflow check.

So no, there is no way to debug it, not because it is simple, because it does nothing, it might as well not be there at all. It is fluff.

That is also another reason why MACROs are discouraged, as they make debugging more difficult. You might as well just create a function.
Last edited on

Xerzi,

Are you saying that if the MACRO is complicated, the compiler is going to do a direct text substitution? and it becomes traceable. or Are you saying it is difficult to debug a program with MACRO no matter what?

I have the actual program that has a macro with pointers to an array of 5 dimensions. will it change anything in debugging.

So far I am beginning to think that you maybe right, MACRO makes debugging more difficult, because it is already kicking my butt.

But it is not smart to say "NO MACRO for me" because I can think of cases were MACRO make the solution so simple, single MACRO can give you the result of addition of macro parameters and you can have addition of different type variable it can be an int, double, long, float, long long, long double and char, but one MACRO is all you need. But if I do it with using function it would have to be a lot of overloaded functions. one function to take care for each data type.

please do not stop responding, I am still trying to figure out how to debug a MACRO and so far you are the only programmer who seem to understand MACRO limitations. In the meantime I will load the more complicated program with a huge MACRO and find out if there is a direct substitution of text.
xerzi,

I just run a more complicated program than the previous hoping that the compiler will do a direct text substitution. However, it did not do a substitution. here is the program

#define INSTRUCTOR_FILE /* STUDENTS: DO NOT DEFINE THIS IN YOUR FILE(S) */

/****************************************************************************
* Everything in this file was written to help test/verify your code and must
* not be altered in any way. Do not rename this file or copy anything from
* it into your file(s). This file does not necessarily represent good coding
* technique, proper formatting/style, or meet the requirements your code must
* meet. You do not need to understand the code in this file to write yours.
***************************************************************************/
#ifdef INSTRUCTOR_FILE

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include "C2A4E2_m5D.h"

#define D_A 2
#define D_B 3
#define D_C 4
#define D_D 5
#define D_E 6

int main(void)
{
int ix0, ix1, ix2, ix3, ix4;
int foo[D_A][D_B][D_C][D_D][D_E];
double bar[D_A][D_B][D_C][D_D][D_E];
long big[D_E][D_D][D_C][D_B][D_A];
float deal[D_E][D_D][D_C][D_B][D_A];

/* seed random # generator */
srand((unsigned)time(NULL));
/* store all values before testing any */
for (ix0 = 0; ix0 < D_A; ++ix0)
for (ix1 = 0; ix1 < D_B; ++ix1)
for (ix2 = 0; ix2 < D_C; ++ix2)
for (ix3 = 0; ix3 < D_D; ++ix3)
for (ix4 = 0; ix4 < D_E; ++ix4)
{
foo[ix0][ix1][ix2][ix3][ix4] = rand();
bar[ix0][ix1][ix2][ix3][ix4] = rand() + rand() / 321.0;
}

for (ix0 = 0; ix0 < D_E; ++ix0)
for (ix1 = 0; ix1 < D_D; ++ix1)
for (ix2 = 0; ix2 < D_C; ++ix2)
for (ix3 = 0; ix3 < D_B; ++ix3)
for (ix4 = 0; ix4 < D_A; ++ix4)
{
big[ix0][ix1][ix2][ix3][ix4] = rand();
deal[ix0][ix1][ix2][ix3][ix4] = rand() + rand() / 123.0F;
}

/* Test all stored values. */
for (ix0 = 0; ix0 < D_A; ++ix0)
for (ix1 = 0; ix1 < D_B; ++ix1)
for (ix2 = 0; ix2 < D_C; ++ix2)
for (ix3 = 0; ix3 < D_D; ++ix3)
for (ix4 = 0; ix4 < D_E; ++ix4)
{
if (m5D((int *)foo, ix0, ix1, ix2, ix3, ix4, D_B, D_C,
D_D, D_E) != foo[ix0][ix1][ix2][ix3][ix4])
{
fprintf(stderr, "Error: foo[%d][%d][%d][%d][%d]\n",
ix0, ix1, ix2, ix3, ix4);
return EXIT_FAILURE;
}
if (m5D((double *)bar, ix0, ix1, ix2, ix3, ix4, D_B, D_C,
D_D, D_E) != bar[ix0][ix1][ix2][ix3][ix4])
{
fprintf(stderr, "Error: bar[%d][%d][%d][%d][%d]\n",
ix0, ix1, ix2, ix3, ix4);
return EXIT_FAILURE;
}
}

for (ix0 = 0; ix0 < D_E; ++ix0)
for (ix1 = 0; ix1 < D_D; ++ix1)
for (ix2 = 0; ix2 < D_C; ++ix2)
for (ix3 = 0; ix3 < D_B; ++ix3)
for (ix4 = 0; ix4 < D_A; ++ix4)
{
if (m5D((long *)big, ix0, ix1, ix2, ix3, ix4, D_D, D_C,
D_B, D_A) != big[ix0][ix1][ix2][ix3][ix4])
{
fprintf(stderr, "Error: big[%d][%d][%d][%d][%d]\n",
ix0, ix1, ix2, ix3, ix4);
return EXIT_FAILURE;
}
if (m5D((float *)deal, ix0, ix1, ix2, ix3, ix4, D_D, D_C,
D_B, D_A) != deal[ix0][ix1][ix2][ix3][ix4])
{
fprintf(stderr, "Error: deal[%d][%d][%d][%d][%d]\n",
ix0, ix1, ix2, ix3, ix4);
return EXIT_FAILURE;
}
}

--ix0, --ix1, --ix2, --ix3, --ix4;
if (m5D((long *)big, ix0 + 1 - 1, ix1 + 2 - 2, ix2 + 3 - 3, ix3 + 4 - 4,
ix4 + 5 - 5, D_D + 4 - 4, D_C + 3 - 3, D_B + 2 - 2, D_A + 1 - 1) !=
big[ix0][ix1][ix2][ix3][ix4])
{
fprintf(stderr, "Error 2: big[%d][%d][%d][%d][%d]\n",
ix0, ix1, ix2, ix3, ix4);
return EXIT_FAILURE;
}

printf("Success!\n");
return EXIT_SUCCESS;
}
#endif


AND THIS IS THE MACRO: defined in my header file: ptr is the pointer to the array of 5 dimension with the following parameters:

A. ptr – a pointer to the first element of a block of memory being used as a 5-
dimensional array
B. idx0, idx1, idx2, idx3, idx4 – indices of the desired element of the array
C. dim1, dim2, dim3, dim4 – the rightmost 4 dimensions of the 5-dimensional
array (no dim0)

#define m5D(ptr, idx0, idx1, idx2, idx3, idx4, dim1, dim2, dim3, dim4) \
((*ptr + (idx0 * dim1 * dim2 * dim3 * dim4) + (idx1 * dim2 * dim3 * dim4) \
+ (idx2 * dim3 * dim4) + (idx3 * dim4) + (idx4)))


http://sources.redhat.com/gdb/onlinedocs/gdb.html#Macros

> Are you saying that if the MACRO is complicated, the compiler is going to do a direct text substitution?
No, the preprocessor always does text substitution.
The compiler may kill useless code.

By the way your parenthesis are wrong
It should be #define myTest(a) (a)[0] + (a)[1] and the call simply myTest(x)
Ne555,

Ok, so the preprocessor does a direct substitution and the compiler just optimize the code.

But my bottom line question is, will I be able to debug it or as Xerzi is saying is it difficult. because I will not see the direct substitution of text.
You can't debug it since your code that is displayed will not show the replaced text.

Just make an inline function. It works exactly the same except you can actually trace through it with a debugger.
Firedraco,

Thanks for getting in the conversation. I agree with you I can trace using the inline function. and if I remove the word inline it is just a regular function.

The only problem is the specification of the program, I can only write one function or one MACRO that can return a type int or type double or type Long or type float, meaning any type in the parameters will work. If I do a function I would have to write multiple overloaded function one for each datatype of parameters.

So I am now convinced that I do not have any choice and just for testing purposes, in order to check the logic of the MACRO I would have to write a function, same logic as the MACRO, for each data type.

Does everybody concur or are you still thinking it could be done?

closed account (o1vk4iN6)

But it is not smart to say "NO MACRO for me" because I can think of cases were MACRO make the solution so simple, single MACRO can give you the result of addition of macro parameters and you can have addition of different type variable it can be an int, double, long, float, long long, long double and char, but one MACRO is all you need. But if I do it with using function it would have to be a lot of overloaded functions. one function to take care for each data type.

...

The only problem is the specification of the program, I can only write one function or one MACRO that can return a type int or type double or type Long or type float, meaning any type in the parameters will work. If I do a function I would have to write multiple overloaded function one for each datatype of parameters.


This is the reason why templates were added into C++, if you are only using C though then you have to accept the trade off for doing less work and that is making it harder to debug.
Thanks for the help, I got my solution figured out but without your help, Firedraco and ne555 I would still be trying to figure out how to do a trace on a MACRO.

Unless I find another way of debugging a MACRO this would be my procedure for now. Convert my MACRO into a function with the same identical logic as the MACRO just to verify that the logic is correct and when I am satisfied convert it back to a MACRO. Not the best way to do it but at least it works.
Most compiler's will allow you to stop the compilation process after the preprocessing is done if you really need to see what's happening via preprocessor macros.

gcc: http://ascending.wordpress.com/2007/03/30/tip-check-the-cc-preprocessor-output/
VS: http://prashantshelar.blogspot.com/2012/04/how-to-view-preprocessor-output-using.html
cire,

I went to the site found the instruction how to view the output of the preprocessor. Is this file for viewing only or could I use it to trace/debug my program
I suppose you could compile the preprocessed files normally and trace it that way, but I think the primary use would be to view how the macro is expanded when you suspect it isn't behaving the way you expect it to.
Topic archived. No new replies allowed.