# Removing functions from builds

This topic is 4606 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

This is a pretty simple question, but I've never actually seen it discussed before. Is there a nice way to remove a function-call completely from the release build of your application without using #ifdef type branches all over? Here's my simple, brute force method of doing this. This is a task-logging routine that much of my engine uses to track progression of tasks:
#ifdef _DEBUG
VOID ScLog(Val_SystemLog type,const CHAR *Format,...);
#else
inline VOID ScLog(Val_SystemLog type,const CHAR *Format,...) {}
#endif
Then of course, I have to #ifdef _DEBUG the actual implementation in the cpp module. I'm not even sure this will remove the function-call overhead, but I can't imagine why it wouldn't. Guess I could look at the ASM result. Anyway, are there better ways to accomplish this? If it seems like I'm asking a dumb question, I probably am. Please feel free to provide the dumb answer [wink]

##### Share on other sites
You know that no functions are inlined in debug builds anyway... Right?

##### Share on other sites
Quote:
 Original post by Andrew RussellYou know that no functions are inlined in debug builds anyway... Right?

He was inlining it when _DEBUG was not defined, not the other way around.

To the OP: I highly doubt there is a way other than using the preprocesser. That's what it's for, after all. You see this sort of thing in stardard libraries:
#ifdef _DEBUG#define ASSERT(TEST) if(!(TEST)) { MessageBox(0, #TEST, "Assertion Failure", MB_OK | MB_ICONERROR); } else (void)0#else#define ASSERT(TEST)#endif

Of course, empty macros like this will only work if either a)you're using a macro or b)the function it's replacing doesn't have any overloads or default values. If it has either, your method is better.
Quote:
 I'm not even sure this will remove the function-call overhead, but I can't imagine why it wouldn't.

If your compiler doesn't remove the overhead when you're optimizing, you MUST get a new compiler.

##### Share on other sites
Quote:
 Original post by ErzengeldeslichtesHe was inlining in when _DEBUG was not defined, not the other way around.

Exactly - he was pointing out that it was redundant.

##### Share on other sites
You could just #define ScLog(...) to remove the function call without the need for #ifdef. Or #define ScLog(Type, Format, ...) a macro to override the function call with "inline" code. In both of these options, the function still remains in the resulting object code, although its never called. This works because the preprocessor nabs the function call before the compiler tries to parse it. If you want to completely remove the function from existance, you'll have to wrap the function body in #ifdef ScLog/#endif. Otherwise, make sure you don't #define ScLog for the unit that contains the function body, otherwise you'll end up with something like this:

VOID ScLog(Val_SystemLog type,const CHAR *Format,...) {
// code goes here
}

...becomes...

VOID {
// code goes here
}

[Edited by - dcosborn on July 9, 2005 8:30:43 AM]

##### Share on other sites
Quote:
Original post by Nitage
Quote:
 Original post by ErzengeldeslichtesHe was inlining in when _DEBUG was not defined, not the other way around.

Exactly - he was pointing out that it was redundant.

No, he said "no functions are inlined in debug builds". How is this pointing out redundancy? In the debug build, the OP is not inlining, the function actually provides code. However, in the release build (when inling is useful) he inlines an empty function (which the compiler would inline anyway, but on that note, ALL inline declarations are "redundant" (more irrelevant)--the compiler will do what it darn well pleases.)

##### Share on other sites
I don't know if you guys noticed, but when _DEBUG is not defined the function has an empty body (I think that's how it's called) there, so I guess that what the OP wants is that when in release mode, the function won't be called.

@OP: If you're using Microsoft Visual Studio compiler you should be able to do this:
#ifdef _DEBUG	VOID ScLog(Val_SystemLog type,const CHAR *Format,...);#else#	define ScLog __noop#endif

##### Share on other sites
Quote:
Original post by Erzengeldeslichtes
Quote:
Original post by Nitage
Quote:
 Original post by ErzengeldeslichtesHe was inlining in when _DEBUG was not defined, not the other way around.

Exactly - he was pointing out that it was redundant.

No, he said "no functions are inlined in debug builds". How is this pointing out redundancy? In the debug build, the OP is not inlining, the function actually provides code. However, in the release build (when inling is useful) he inlines an empty function (which the compiler would inline anyway, but on that note, ALL inline declarations are "redundant" (more irrelevant)--the compiler will do what it darn well pleases.)

Actually, I was working off the assumption that Jiia had simply removed the code from the {} to make his post shorter. So, given my assumption, I was correct [wink].

If there is no code to be run, his existing solution or Kamikaze15's or your own (Erzengeldeslichtes, for those people playing at home) is just fine. In theory, they should end up with same code (or lack thereof). This might not work if, say, you take the address of ScLog.

Jiia's original solution is nice to namespace as a plus. The other's have the advantage of giving 100% assurance that there will be no code generated.

Kamikaze15's has the negitive of being Microsoft-specific. Although the success of Jiia's original solution will also depend on the compiler.

##### Share on other sites
Wow, it looks like Microsoft built their __noop routine just for my situation. For readability sake, though, I would like it to be obvious as to what is happening. And it seems from the confusion of my post, my solution isn't very clear either.

As for the #define ScLog(...), will this actually work? I wasn't aware that macros could accept a variable argument list? A macro was my first guess to this problem, and that was what prevented me from using it in this function's situation.

Lastly, regarding the inline keyword. I don't see how it's use is redundant at all. How else could it be done? If I define the function body without the keyword, empty or not, in the header file, the compiler will have a fit. The resulting code would be included in every module that contains it. Is this incorrect?

edit:
Just to prevent further confusion, my goal really is to remove the function body. So what you see in my original post is the actual code. Including the empty {} and the ,... argument format. Those are not lazy posting placeholders :)

##### Share on other sites
As long as we're talking compiler specific options, some advice for the gcc users.

##### Share on other sites
I just tested your inline solution on my compiler (MSVC++ 7.1) on release mode and ran the disassembler and the there was no code related to the function at all, it even jumped a breakpoint I've set there, so you should be fine using inline.

##### Share on other sites
I have an occasion used sizeof as the moral equivalent of __noop when such a thing was necessary and I could get away with it.

##### Share on other sites
One trick that provides the most compatibility across compilers is to do something like the following:

#ifdef _DEBUG#define FUNC(x) printf x#else#define FUNC(x)#endifvoid somefunction(char *ptr1, int val){    FUNC(("nothing to see here. %s - %d\n", ptr1, val));}

This comes in handy if you need to pass a variable number of arguments but need the code removed for release builds. You can also do something like the following to reduce the number of macros needed for calls that are only used once or twice:

#ifdef _DEBUG#define FUNC(x, y) x y#else#define FUNC(x, y)#endifvoid somefunction(char *ptr1, int val){    FUNC(printf, ("nothing to see here. %s - %d\n", ptr1, val));}

##### Share on other sites
I'm wondering if the compiler will be okay handling more complex situations. Such as..

ScLog( SCLOG_WARNING, "%s %d %f", StringFunc(), rand() % 5, Time * 200.0f );

I can test it out. I'm just being lazy and can't remember where to find that ASM output option. I realize that some types of code in the parameter list would (or should) be included. But I wonder if that would actually be pulled out of the function argument list and called normally? It's no big deal, I'm just curious. I wouldn't include vital code in there anyways.

edit @ Helter Skelter: That's pretty clever. Another macro trick I was unaware of.

##### Share on other sites
Quote:
 Original post by Jiiaedit @ Helter Skelter: That's pretty clever. Another macro trick I was unaware of.

Yeah it's pretty neat. Been using it for about a decade and I've only run into one compiler/preprocessor that didn't like it.

Also keep in mind that whether you use a FUNC like macro or the __noop directive statements like the following need to be avoided:

funcmacro(a++);

In release mode "a++" never happens. Now you would expect that the use of __noop would warn you about this but it doesn't.