skip to Main Content

while developing in Xcode it is common to switch between Debug and Release mode and using some parts of code in Debug mode only while not using some in Release mode.

I often throw out NSLog code by some #define rule that lets the Pre-compiler parse out those commands that are not needed in a Release. Doing so because some final testing needs proof everything works as expected and errors are still handled properly without messing some NSLog i possibly forgot. This is in example of importance in audio development where logging in general is contra productive but needed while debugging. Wrapping everything in #ifdef DEBUG is kinda cumbersome and makes code lock wild, so my #defines are working well to keep code simple and readable without worrying about NSLog left in releases while still Logging on purpose if needed. This praxis works really well for me to have a proper test scenario with pure Release code.

But this leads to compiler warnings that some variables are not used at all. Which is not much of a problem but i want to go one step ahead and try to get rid of those warnings also. Now i could turn those warnings off in Xcode but i try to find a way to keep those and just getting rid of them for my NSLog overruled #defines

So instead of logging against dev>null i throw out (nullify) all code that is wrapped by NSLog() and use some extra defined rule called ALLWAYSLog() that keeps NSLog in Releases on purpose and also changes NSLog to fprintf to avoid app origin and time prints.
Here my rules..

#ifdef DEBUG
 #define NSLog(FORMAT, ...) fprintf(stderr, "%s n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String])
#else
 #define NSLog(FORMAT, ...) {;}
#endif
#define ALLWAYSLog(FORMAT, ...) fprintf(stderr, "%s n", [[[NSString alloc] initWithFormat:FORMAT, ##__VA_ARGS__] UTF8String])

To get rid of those unused variable warnings we often use

#pragma unused(variablename)

to inform the precompiler we did that on purpose..

Question:
Is it possible to write some #define rule that makes use of #pragma unused(x) ?
Or how to integrate this mentioned way of __unused attribute

2

Answers


  1. Chosen as BEST ANSWER

    after testing and still not believing there is no "official way" of doing this i ended up reading my header files again. (usr/include/sys/cdefs.h)

    where __unused is declared as __attribute__((__unused__)).

    This seems the officially way of telling the Apple Clang (GCC) compiler a specific variable will be not used intentionally by placing a __unused directive at the right place in code. In example in front of a variables declaration or after a function declaration and more.. see stackoverflow discussion starting 2013 ongoing

    @dbush 's answer was and is nice because it suppresses the unused variable warning by making use of the passed arguments and introducing nullify logic that will do no harm - but will still be executed to find "Expression result unused". That was pretty close to my goal and is possibly still the most simple solution.

    in example:

    #define NSLog(...) (0 && fprintf(stderr,"%s",[[NSString alloc] initWithFormat:__VA_ARGS__].UTF8String))
    
    // applied to
    int check = 333;
    NSLog(@"findMeAgainInPreProcess %d",check);
    
    // preprocesses to
    int check = 333;
    {0 && fprintf(__stderrp,"%s n",[[NSString alloc] initWithFormat:@"findMeAgainInPreProcess %d",check].UTF8String);};
    

    While this will not print anything, the compiler knows the expression is unused then.

    But this left me with the question how unused marking is done properly. Trying a reciprocal approach distinguish Debug and Release to make use of __unused again in combination with my first approach like so...

    #define ALLWAYSLog(...) fprintf(stderr,"%s n",[[NSString alloc] initWithFormat:__VA_ARGS__].UTF8String)
    #ifdef DEBUG
    #define IN_RELEASE__unused
    #define NSLog(...) ALLWAYSLog(__VA_ARGS__)
    #else
    #define IN_RELEASE__unused __unused
    //#define NSLog(...) (0&&ALLWAYSLog(__VA_ARGS__)) //@dbush solution
    //#define NSLog(...) NSCAssert(__VA_ARGS__,"")
    //#define NSLog(...) {;}
    #define NSLog(...) /*__VA_ARGS__*/
    #endif
    

    In Debug it will not silence the unused variable warning by parsing out the directive itself and in Release it will exchange IN_RELEASE__unused to __unused according to the macro and silence it. This is a little extra work but could help to see which parts are unused on purpose.

    Means i can type like below..

    IN_RELEASE__unused int check = 333;
    NSLog(@"findMeAgainInPreProcess %d",check);
    
    // produces for DEBUG
    int check = 333; //no warning, var is used below
    fprintf(__stderrp,"%s n",[[NSString alloc] initWithFormat:@"findMeAgainInPreCompile %d", check].UTF8String);
    
    // produces for RELEASE
    __attribute__((__unused__)) int check = 333; //no warning intentionally
    ; // no print, nothing
    

    This keeps NSLog in place (in code), marks the unused variables to silence the warning properly and NSLog gets parsed out completely in Release. And i can still force prints for both modes with the introduced ALLWAYSLog.

    Conclusion: dbush's solution is still more straight forward.


  2. In the #else case, you can put the function call on the right side of the && operator with 0 on the left side. That will ensure that variables are "used" while also ensuring that the function doesn’t actually get called and that the parameters are not evaluated.

    #ifdef DEBUG
     #define NSLog(FORMAT, ...) fprintf(stderr, "%s n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String])
    #else
     #define NSLog(FORMAT, ...) (0 && fprintf(stderr, "%s n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]))
    #endif
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search