Macro Destroyer

J

JKop

I was doing some Win32 programming today, having to include the file
"windows.h". Anyway, I'm thinking of writing a program that'll work like so:

macrodestroyer.exe windows.h

What this program will do is scour through the file, replacing all macros
with global const variables and inline functions. So for instance, if you
have:

#define MAX_LOADSTRING 100

It'll become:

unsigned const MAX_LOADSTRING = 100;

And if you have:

#define Minus5(t) (t-5)

Then'd be turned into

template <class T,class R>
inline T Minus5(R r)
{
return (t-5);
}


Or something along those lines.

Anyway...

The main benefits of this would be:

A) Follows scoping rules, and you could wrap "windows.h" in a namespace, eg:

namespace Win { #include "windows.h" }


B) You wouldn't have the problem of:

SomeMacro(++i);

in that it may increment it more than once.



Also, I would turn:

#define LRESULT long;

into:

typdef long LRESULT;


Anyway, before I get going on this little pet project, has this been done
before?

Any ideas, comments at all?


-JKop
 
H

hari4063

It is OK project, but it is highly chance that is not work OK. Reason for
this my be different meaning of:

#define MACROTYPE type*

and

typedef type MYTYPE

This two forms are different in term of:

MACROTYPE a, b;

is:
type *a, b; // b is not pointer to type

but in real typedef (MYTYPE)

MYTYPE a, b; // a and b are pointers.

I realy do not know is something like this is present in windows.h so than
your project have chance :)
 
J

JKop

hari4063 posted:
It is OK project, but it is highly chance that is not work OK. Reason
for this my be different meaning of:

#define MACROTYPE type*

and

typedef type MYTYPE

This two forms are different in term of:

MACROTYPE a, b;

is:
type *a, b; // b is not pointer to type

but in real typedef (MYTYPE)

MYTYPE a, b; // a and b are pointers.

I realy do not know is something like this is present in windows.h so
than your project have chance :)


That's a very good thing to point out, I hadn't thought of that.

I'll look into it...


-JKop
 
I

Ivan Vecerina

JKop said:
I was doing some Win32 programming today, having to include the file
"windows.h". Anyway, I'm thinking of writing a program that'll work like
so:

macrodestroyer.exe windows.h

What this program will do is scour through the file, replacing all macros
with global const variables and inline functions. So for instance, if you
have:
[examples reordered for discussion]
#define MAX_LOADSTRING 100
It'll become:
unsigned const MAX_LOADSTRING = 100;
Hum, why *unsigned* ? (the value could be -100)
I tend to prefer enum { MAX_LOADSTRING = 100 }; for such things anyway.

[ incorrect trailing ; removed from the next line ]
#define LRESULT long
into:
typdef long LRESULT;

Note that the two previous cases will not always be easy to distinguish.
Consider:
#define THIS_STATUS_CODE SOME_PREVIOUS_ID
Should this become a typedef or a const?

You may need to parse #include-d files to find out...
The problem is aggravated by the fact that SOME_PREVIOUS_ID
may not even have been seen when the macro is defined.
How will you translate:
#define a b
// ... many lines or files later:
#define b int // or could be 0x00000000 instead of 'int'

Also, in <windows.h>, you will find a lot of macros such as:
#define GetWindowText GetWindowTextA
Which would best be translated into something like (e.g.):
inline BOOL GetWindowText(HANDLE h, CHAR* p)
{ return GetWindowTextA(h,p); }

These may additionally be conditionally compiled:
#ifndef UNICODE
#define GetWindowText GetWindowTextA
#else
#define GetWindowText GetWindowTextW
#endif
#define Minus5(t) (t-5)

Then'd be turned into

template <class T,class R>
inline T Minus5(R r)
{
return (t-5);
}
Beware that this may not always be equivalent.
In particular, it may generate additional member copies.

The main benefits of this would be:


A) Follows scoping rules, and you could wrap "windows.h" in a namespace,
eg:

namespace Win { #include "windows.h" }


B) You wouldn't have the problem of:

SomeMacro(++i);

in that it may increment it more than once.
Yes, but then someone will accidentally compile the code
with the original version of <windows.h> and eventually
face strange and unexpected bugs.

Anyway, before I get going on this little pet project, has this been done
before?

Any ideas, comments at all?
As you can tell, this is not a trivial task: you need
a preprocessor, a parser, and probably need to scan
all files together prior to processing.

I sympathize...
but I've given up long ago (locally) modifying files supplied
by a vendor. Better wrap and encapsulate them into
your own files/classes.


Regards,
Ivan
 
H

hari4063

So, ... if you make this project, please pass mail to me (i will be glad to
see this, for free-or-not :)
 
J

JKop

My first task will be:


#pragma once


becomes:


#ifndef INCLUDE_BLAH_HPP
#define INCLUDE_BLAH_HPP

//contents of file

#endif
 
C

Chris Theis

im Newsbeitrag [SNIP]
Hum, why *unsigned* ? (the value could be -100)
I tend to prefer enum { MAX_LOADSTRING = 100 }; for such things anyway.

You could also run into trouble with enum. IMHO it would be crucial to check
thoroughly the value of the assignment and produce code accordingly.

[SNIP]

Cheers
Chris
 
C

Chris Theis

JKop said:
I was doing some Win32 programming today, having to include the file
"windows.h". Anyway, I'm thinking of writing a program that'll work like so:

macrodestroyer.exe windows.h

What this program will do is scour through the file, replacing all macros
with global const variables and inline functions. So for instance, if you
have:

#define MAX_LOADSTRING 100

It'll become:

unsigned const MAX_LOADSTRING = 100;

And if you have:

#define Minus5(t) (t-5)

Then'd be turned into

template <class T,class R>
inline T Minus5(R r)
{
return (t-5);
}


Or something along those lines.

Anyway...

The main benefits of this would be:

A) Follows scoping rules, and you could wrap "windows.h" in a namespace, eg:

namespace Win { #include "windows.h" }


B) You wouldn't have the problem of:

SomeMacro(++i);

in that it may increment it more than once.



Also, I would turn:

#define LRESULT long;

into:

typdef long LRESULT;


Anyway, before I get going on this little pet project, has this been done
before?

Any ideas, comments at all?

You know the road to hell is paved with good intentions ;-) Some subtle
issues were already pointed out in other postings and in general the problem
is that you would have to perform a very careful & thorough parsing
(sometimes of the whole project!). Even with that you have a good chance to
screw up in many places because the intention of the #defines are different
and hard to interpret automatically. This will become even more difficult
when they are somehow interlinked.

Generally, fumbling with compiler manufacturer's headers are bound to give
you or somebody else trouble some day.

The idea of replacing the #pragma statement with ordinary include guards is
a good one and should not attract trouble but I'd stay away from the rest.
IMHO you can invest your time in a better way.

Regards
Chris
 
T

Tom Widmer

I was doing some Win32 programming today, having to include the file
"windows.h". Anyway, I'm thinking of writing a program that'll work like so:

macrodestroyer.exe windows.h

What this program will do is scour through the file, replacing all macros
with global const variables and inline functions. So for instance, if you
have:

#define MAX_LOADSTRING 100

It'll become:

unsigned const MAX_LOADSTRING = 100;

You should keep the type the same:

int const MAX_LOADSTRING = 100;
And if you have:

#define Minus5(t) (t-5)

Then'd be turned into

template <class T,class R>
inline T Minus5(R r)
{
return (t-5);
}


Or something along those lines.

That won't work:

Minus5(10); //error, what about the T parameter?
You need "typeof" or similar. e.g.
template <class T>
typeof(t-5) Minus5(T t)
{
return t-5;
}
Anyway...

The main benefits of this would be:

A) Follows scoping rules, and you could wrap "windows.h" in a namespace, eg:

namespace Win { #include "windows.h" }

I can see this having the potential to cause linker errors. The types
will be marked as being in namespace Win, but in fact they are global.
This might cause problems with C++'s typesafe linking (e.g. name
mangling) that extern "C" doesn't fully negate, but you'll have to try
it to be sure.

Tom
 
J

JKop

That won't work:

Minus5(10); //error, what about the T parameter?
You need "typeof" or similar. e.g.
template <class T>
typeof(t-5) Minus5(T t)
{
return t-5;
}


Can the compiler not determine the return type from the return statement?


Off to do some experimentation. . .


-JKop
 
J

JKop

I'm going to start off with a broad checklist on this.

Obviously first of all, I'll deal with #define statements. Here's the kinds:


1) #define DAYS_IN_A_YEAR 365

Note: Will become a global const variable of the type of 365.


2) #define LRESULT long

Note: Will become a typedef


3) #define Minus5(a) (a - 5)

Note: Will become an inline function


4) #define WIN32_LEAN_AND_MEAN

Note: I'll leave these alone.


5) #define public private

Note: A keyword being redefined - there's obviously some sort of intentional
hack going on here, so I'll leave it alone!



After that:

1) #pragma once

Note: Will become inclusion guards.



Any other ideas?


Firstly I'm going to decide how I'll turn:

#define DAYS_IN_A_YEAR 365

into a global const variable. I'll have to devise a way of choosing the
right type...


-JKop
 
I

Ioannis Vranos

JKop said:
I was doing some Win32 programming today, having to include the file
"windows.h". Anyway, I'm thinking of writing a program that'll work like so:

macrodestroyer.exe windows.h

What this program will do is scour through the file, replacing all macros
with global const variables and inline functions. So for instance, if you
have:

#define MAX_LOADSTRING 100

It'll become:

unsigned const MAX_LOADSTRING = 100;

And if you have:

#define Minus5(t) (t-5)

Then'd be turned into

template <class T,class R>
inline T Minus5(R r)
{
return (t-5);
}


Or something along those lines.

Anyway...

The main benefits of this would be:

A) Follows scoping rules, and you could wrap "windows.h" in a namespace, eg:

namespace Win { #include "windows.h" }


B) You wouldn't have the problem of:

SomeMacro(++i);

in that it may increment it more than once.



Also, I would turn:

#define LRESULT long;

into:

typdef long LRESULT;


Anyway, before I get going on this little pet project, has this been done
before?

Any ideas, comments at all?


Well, why waste time with this old code?


In any case, in general if you want to create a program which converts
macro definitions to inline function definitions, etc I think you will
need to read some book about parsing.

If you are only interested about doing this for Win32 facilities, you
have better start reading about .NET and forget that old stuff. :)
 
J

Jay Nabonne

I was doing some Win32 programming today, having to include the file
"windows.h". Anyway, I'm thinking of writing a program that'll work like so:

macrodestroyer.exe windows.h

What this program will do is scour through the file, replacing all macros
with global const variables and inline functions. So for instance, if you
have:
<snip>

It's *really* important to keep in mind that #define's don't cause
anything to happen in the "real" file until invoked. They just define text
replacements for when a macro is eventually used. Here are some fun
cases (off the top of my head - not tested to be compilable):

Case 1

// order isn't important.
#define Y X+100
#define X 5

Case 2

// Usage of numeric #defines in other preprocessor contexts
#define VERSION 1
#ifdef VERSION
....
#endif

Case 2.1

#define VERSION 5
#if VERSION > 4
....
#endif

Case 3

// Definitions are transient and may be undone at any time.
#define X 10

// later, perhaps in a different file
#undef X
#define X 20

Case 4

// Anything with token pasting or stringizing...
#define AGE 29
#define SayAGE(a) puts("My age is " #a)

You can combine the above to your heart's discontent.

I would also be careful about wanting to remove side effects. Unless
you're using it for new code, there may be dependencies on those side
effects in existing code, sad as that may be.

Good luck!

- Jay
 
S

Steven T. Hatton

JKop said:
I was doing some Win32 programming today, having to include the file
"windows.h". Anyway, I'm thinking of writing a program that'll work like
so:

macrodestroyer.exe windows.h

What this program will do is scour through the file, replacing all macros
with global const variables and inline functions. So for instance, if you
have:

This may be very disturbing for you to learn, but you and I think alike.
Just this morning I was thinking about something I was calling anti-macros.
(Kind of like anti-matter, but they won't power a starship.) The idea is
to replace all your macros with the CPP rendering, but store some kind of
tag that will reverse the process. Something like this would go around the
expansion. (There are obvious problems here. It's just a first stab.)

#pragma macro_begin NAME_OF_MACRO
The expanded form of the macro goes here.
#pragma macro_end NAME_OF_MACRO


The motivation for doing things that way would be to revert to the macro
form of the code when desired. I even went so far as to muse about
enhancing the CPP rather than abolishing it ... but that frightened me.

I have some other ideas, but I will probably put them in the KDevelope whish
list before I post them here.
--
"If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true." - Bertrand
Russell
 
S

Steven T. Hatton

JKop said:
Can the compiler not determine the return type from the return statement?

I only wish. The one exception, which I have not explored are the
conversion operator member functions.

What am I missing here?
template <typename T>{ T Minus5(const T& t) { return t - 5;} }



NOTE: The use of 'class' for template parameters rather than 'typename' was
extremely confusing to me when first learning C++. I still find it less
intuitive than using 'typename'.

NOTE: For formal parameters, I always use 'const type& var' rather than
simply 'type var'. I don't recall the exact reasoning, but I was once given
a convincing argument to favor this approach. It has something to do with
passing literals such as '5'.

NOTE: I will do:

template <typename T>{ T f(T t) { return op(t); } } // on one line;

but not

for(int i; i < stop; i++) doit(); // no braces

That last statement would, in my code, be

for(int i; i < stop; i++) { doit(); }

It's just too easy to neglect to notice that doit2() in

for(int i; i < stop; i++)
doit();
doit2();

is not part of the for loop.

The reason I will put the above example on one line is because it allows me
to compact my code which often results in easier comparison of closely
related statements. I wouldn't, however do this:

template <typename T>{ T f(T t) { op2(t); return op(t); } } // BAD;

That starts looking like perl.
--
"If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true." - Bertrand
Russell
 
S

Steven T. Hatton

Chris said:
Generally, fumbling with compiler manufacturer's headers are bound to give
you or somebody else trouble some day.


I agree that windoze.h is not something to try second guessing, but I
believe the general idea of pre-edit macro replacement has (great) merit.
--
"If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true." - Bertrand
Russell
 
C

Chris Theis

Steven T. Hatton said:
I agree that windoze.h is not something to try second guessing, but I
believe the general idea of pre-edit macro replacement has (great) merit.


I absolutely agree with you regarding the merit but I wanted to stress that
this is all but trivial and might become a monstrous task ;-)

Cheers
Chris
 
C

Chris Theis

JKop said:
I'm going to start off with a broad checklist on this.

Just some comments & remarks to make you aware of common pitfalls.
Obviously first of all, I'll deal with #define statements. Here's the kinds:


1) #define DAYS_IN_A_YEAR 365

Note: Will become a global const variable of the type of 365.


2) #define LRESULT long

Note: Will become a typedef

It will be crucial how to differentiate between case 1 and 2. The
straightforward strategy might be to check the second argument of #define
and if it´s a number then you´ll have a constant. Otherwise a typedef is
what you´re looking for. But wait for a moment because the world is a little
more complicated. What about the following nested (and probably spread over
different files) declaration:

#define X_VAL 1
#define AXIS_X X_VAL

What will be the result of the second #define transformation? You can now
say - "piece of cake", I´ll only create typedefs if the second argument is a
token specifying a data-type like int, long, etc. Unfortunately there is
more trouble in store & especially using the MS windows headers you´ll have
to face it. Think of the following:

#define BYTE char
#define PCHAR BYTE*

or

#define BYTE char
#define MYCHAR BYTE

Furthermore keep in mind that the respective definitions might be spread
over different files!
3) #define Minus5(a) (a - 5)

Note: Will become an inline function


4) #define WIN32_LEAN_AND_MEAN

Note: I'll leave these alone.


5) #define public private

Note: A keyword being redefined - there's obviously some sort of intentional
hack going on here, so I'll leave it alone!

If you encounter such a hack there is certainly something very wrong
regarding some design issue ;-)
After that:

1) #pragma once

Note: Will become inclusion guards.

That´s a good idea & easy to solve.
Any other ideas?


Firstly I'm going to decide how I'll turn:

#define DAYS_IN_A_YEAR 365

into a global const variable. I'll have to devise a way of choosing the
right type...

If you´re really going for it then I wish you good luck and would recommend
to read up on parsing.

Cheers
Chris
 
K

Karl Heinz Buchegger

JKop said:
[snip]

Any other ideas?

Just a few weeks back I did this:

#define LoadDLLFunction(name) \
(*(FARPROC*)&name = GetProcAddress( m_hDLL,#name)); \
if( name == NULL ) { \
AfxMessageBox( "DLL does not export:\n" #name ); \
}

LoadDLLFunction( func1 );
LoadDLLFunction( func2 );

It is used to lookup a function 'func1' in a DLL and store a pointer
to it in a function pointer variable with the same name as the function.
 
S

Steven T. Hatton

Chris said:
I absolutely agree with you regarding the merit but I wanted to stress
that this is all but trivial and might become a monstrous task ;-)

It depends on what you want to accomplish. If your goal is to be 100%
comprehensive, you will end up with a rather large file in your edit buffer
if you have something such as #include <iostream> and a few of your own
headers as well.

I'm thinking along the lines of cookie-cutter code. Suppose you want to
create a unit test framework using a standard format for your test
functions. I've seen this done using macros. It's how the Boost unit test
stuff works. Basically you pass as macro arguments things such as the
names of the functions you want to invoke. These are expanded to use both
the function and a string representation of the function for output
purposes, etc. I'd be happy to have a tool along the lines of
tempotemplates (which will work), rather than CPP macros to do all of this.

But people do use macros, and they have the advantage (and shortcoming) that
they can be changed at one point in the code resulting in global changes.
And they are part of the C++ Standard, so they port.
--
"If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true." - Bertrand
Russell
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top