How can I remove these #define's from the code and change them to something better?

Hey there, I have a few questions about the #define's being used in this code, I never use them in my own code, and I'm not exactly sure how the following ones work, so I'd like to see what I can do differently. I read that std::function might be an alternative to some #defines, and I know that it's bad practice to use them in C++ which is why I want to get rid of them.

Here are some examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#define A( s ) #s
#define OPTION(type, var, val) Var<type> var = {A(var), val}

template <typename T = bool>
class Var {
public:
	std::string name;
	std::shared_ptr<T> value;
	int32_t size;
	Var(std::string name, T v) : name(name) {
		value = std::make_shared<T>(v);
		size = sizeof(T);
	}
	operator T() { return *value; }
	operator T*() { return &*value; }
	operator T() const { return *value; }
};


So this basically has two defines at the top, and the way that the defines are being used is like: OPTION(bool, isMale, true)

I tried tracing this, and what it seems to be the equivalent to is:

 
Var<bool> isMale = {#isMale, true}; 


which makes no sense to me. The main part that is confusing me is the:
 
#define A(s) #s 


I don't really know why that is used, and for all i know, it just replaces s with #s. Does this pound symbol have some special meaning inside of the define? What could I change this to, in order to get the same result?

Here's my next example:

1
2
3
4
5
#define NETVAR(type, name, table, netvar)                           \
    type& name##() const {                                          \
        static int _##name = NetvarSys::Get().GetOffset(table, netvar);     \
        return *(type*)((uintptr_t)this + _##name);                 \
    } 


and this is used to make functions inside of a class.

If you were to say something like this:
 
NETVAR(int32_t, test, "table", "variable")


would it be the same as the following?

1
2
3
4
int32_t test() const{
    static int a = NetvarSys::Get().GetOffset("table", "variable");
    return *(int32_t*)((uintptr_t)this + a);
}


Edit: also removing the backslashes at the end of each line in the second example breaks it. No clue what those do either.

Thanks for any help, i'd really like to get rid of all these #defines and use something else in their place, but the first step is really just understanding why they are being used like this.
Last edited on
these are C preprocessor macros.
to remove them you need to craft a function that does the same things, or maybe a lambda, or whatever else may be appropriate.
the \ means 'the next line also is part of this thing' so yea, that will break it :)

So you need to understand what the macro does, and then replace it with a normal function. Understanding what they do may take a while, the syntax is funky and difficult. I have forgotten much of it, they were not used a lot after c++ 1998 standard.

talking about bad practice, though:
IMHO screwing with something that works is bad practice.
If you need to change it because its being updated, fine. But if it works, leave it alone, even if its 'unclean'. "fixing" it just means having debug it and validate that its the same as it was before ... a lot of work to get back to where you were.

the bad practice note is more about "do not write new code this old way" than "fix every instance of it that you find". At least to me, I see it this way. Some people will disagree and insist on doing the refactor work.

there are a small # of things macros can do that code cannot, or used to be. Mostly debugging info, such as 'what is the current scope (function name)'. This is because that info is in special macro variables that are not as readily available outside macros (or again, used to be?)
Last edited on
The # in the preprocessor macro is the preprocessor "stringify" operator.
It yields the parameter in quotes, so the result would be:

 
Var<bool> isMale = {"isMale", true};

## is the preprocessor token concatenation operator.
The first use of it (before the ()) is pointless.
The other two uses simply prepend an underscore to the given token.
So the result would be:

1
2
3
4
int32_t test() const{
    static int _test = NetvarSys::Get().GetOffset("table", "variable");
    return *(int32_t*)((uintptr_t)this + _test);
}

I have no idea where you got the a's from, although I suppose the variable name doesn't actually matter, so maybe that's what you were implying.
Last edited on
IMHO screwing with something that works is bad practice.

I agree, but some people want to fix things even if they are not broken.
I agree that macros can be the devil incarnate. However, my advice as per others, is that if an existing macro is working, don't mess with it - especially if it's not a simple one and uses # or ##. Note that the macros are expanded by the pre-processor before the C++ compiler ever sees the resultant code. if you need to modify code that uses a macro, then fine, replace it. BUT IMO I wouldn't just get rid of them for the sake of removing them.

Depending upon the compiler, you may also be able to view the processed code. See
https://stackoverflow.com/questions/985403/seeing-expanded-c-macros
Topic archived. No new replies allowed.