Obj-C, using ifndef and target parameters to only printf debug lines? - iphone

I've been happily using a replacement for NSLog called DLog so that I don't have to worry about debugging being left in a release build.
#ifndef NDEBUG
# define DLog(FORMAT, ...) printf("%s\n",
[[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
#else
# define DLog(...)
#endif
However, I'd like to do some a bit more complicated, I have numerous targets with debug parameters and I'd like to include two parameters to enable me to get debugging information.
I had hoped I could use, something like this...
#ifndef NDEBUG
# define DLog(FORMAT, ...) printf("%s\n", ...
#else
#ifdef TESTFLIGHT && FREEMIUM
# define DLog(FORMAT, ...) printf("%s\n", ...
#else
# define DLog(...)
#endif
But it's not as simple as that.. I'm probably missing something obvious?
I've googled the problem but can't find the AND operator for this purpose and nested IF statements seems a problem too ?

When you're using the existence of the definition like this, to combine use this syntax:
#if defined TESTFLIGHT && defined FREEMIUM
(#ifdef is shorthand for #if defined).
Use #elif for "else if" to cascade without nesting.
You can use the boolean operator straight-up like you want if you're defining the constant to be equal to something (e.g. 1) rather than just being "defined". e.g.
#define TESTFLIGHT 1
#define FREEMIUM 1
...
#if TESTFLIGHT && FREEMIUM

You should use "#elif" to make an else if, instead of nested ifs.
And you can can use the #if defined(TESTFLIGHT) && defined(FREEMIUM), as said on the other answers. So :
#ifndef NDEBUG
# define DLog(FORMAT, ...) printf("%s\n", ...
#elif TESTFLIGHT && FREEMIUM
# define DLog(FORMAT, ...) printf("%s\n", ...
#else
# define DLog(...)
#endif

You need to use "normal" #if:
#if defined(TESTFLIGHT) && defined(FREEMIUM
#ifdef FOO is simply short for #if defined(FOO)
You're also missing an #endif. So complete, it's:
#ifndef NDEBUG
# define DLog(FORMAT, ...) printf("%s\n", ...
#else
# if defined(TESTFLIGHT) && defined(FREEMIUM)
# define DLog(FORMAT, ...) printf("%s\n", ...
# else
# define DLog(...)
# endif
#endif

Related

C preprocessor: include based on define

How can I include a file or another, based on the value of a defined string?
This doesn't work:
#define VAR VALUE_A
#if VAR == "VALUE_A"
#include "a.h"
#elif VAR == "VALUE_B"
#include "b.h"
#endif
If it's important, I'm not actually defining VAR, I'm passing it down from the command-line via gcc -D NAME=VALUE.
The == operator does not compare strings. But you have a couple of other options to configure your includes. In addition to the solutions already mentioned in other answers, I like this one because I think it is quite self-explanatory.
/* Constant identifying the "alpha" library. */
#define LIBRARY_ALPHA 1
/* Constant identifying the "beta" library. */
#define LIBRARY_BETA 2
/* Provide a default library if the user does not select one. */
#ifndef LIBRARY_TO_USE
#define LIBRARY_TO_USE LIBRARY_ALPHA
#endif
/* Include the selected library while handling errors properly. */
#if LIBRARY_TO_USE == LIBRARY_ALPHA
#include <alpha.h>
#elif LIBRARY_TO_USE == LIBRARY_BETA
#define BETA_USE_OPEN_MP 0 /* You can do more stuff than simply include a header if needed. */
#include <beta.h>
#else
#error "Invalid choice for LIBRARY_TO_USE (select LIBRARY_ALPHA or LIBRARY_BETA)"
#endif
Your users can now compile with:
$ cc -DLIBRARY_TO_USE=LIBRARY_BETA whatever.c
You can use #ifdef or #ifndef for conditional includes.
#ifdef VALUE_A
#include "a.h"
#endif
#ifdef VALUE_B
#include "b.h"
#endif
The closest possilibility I can think of is to utilize third form of #include directive (C11 ยง6.10.2/4), namely define VAR with value, that holds actual header filename:
#define VAR "a.h"
then just use the following:
#include VAR

Why does Perl access to cross-platform packed structs not work with SWIG?

Working from:
Is ignoring __attribute__((packed)) always safe in SWIG interfaces?
Visual C++ equivalent of GCC's __attribute__ ((__packed__))
My .i does:
#define __attribute__(x)
then uses %include to include my cross-platform definition of PACK():
#if defined(SWIG)
#define PACK(...) VA_ARGS
#elif defined(_MSC_VER)
#define PACK(__Decl__) __pragma(pack(push, 1)) __Decl__ __pragma(pack(pop))
#else // GCC
#define PACK(__Decl__) __Decl__ __attribute__ ((packed))
#endif
Then I have code like:
PACK(
typedef struct {
uint8_t something;
uint32_t more;
} ) aName;
With earlier versions of the PACK() macro, I got syntax error from SWIG on the typedef line. Now I get past that but when compiling the SWIG-generated .c file, I have get and set functions that complain aName doesn't exist. The messages are like (edited):
libudr_perl_swig.c: In function '_wrap_aName_set':
libudr_perl_swig.c:2367:20: error: expected identifier or '(' before
'=' token libudr_perl_swig.c: In function '_wrap_aName_get':
libudr_perl_swig.c:2377:3: error: expected expression before 'aName'
SWIG sort of seems to know about my struct -- it creates access functions -- but the doesn't expose them enough that the access functions can find it.
Before I started to make this cross-platform -- when it was still Linux-only with __attribute__ ((packed)) -- it worked in SWIG. And it still works in Linux. So there appears to be something about SWIG's interpretation of PACK() that is flawed.
The old way generated a lot of per-field code like:
XS(_wrap_aName_something_set) {
{
aName *arg1 = (aName *) 0 ;
...
the new way generates a little per-struct code like:
SWIGCLASS_STATIC int _wrap_aName_set(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {
MAGIC_PPERL
{
Why should my PACK() (which should be a no-op in SWIG) do that?
Googling "cpp standard variadic macros" leads to http://en.wikipedia.org/wiki/Variadic_macro which notes the expansion of ... is __VA_ARGS__, not VA_ARGS (as I had found somewhere). When I change my macro definition to be:
#if defined(SWIG)
#define PACK(...) __VA_ARGS__
#elif defined(_MSC_VER)
#define PACK(__Decl__) __pragma(pack(push, 1)) __Decl__ __pragma(pack(pop))
#else // GCC
#define PACK(__Decl__) __Decl__ __attribute__ ((packed))
#endif
it works.

How to skip a line of code inside a class during compiling

I have allocated and initialized a class file which is not in the project workspace (don't have a file to import).Normally it would throw an error like Use of undeclared identifier classname.Here i want to skip this error make the build success.Is there any pragma to skip these kind of error's.
Wrap the code around #ifdef and #endif macros and do not define the macro name that is used.
Example
- (void)myMethod
{
// ....
#ifdef MYMACRO
// Here you need not #import ABC.h
ABC *abc = [[ABC alloc] init];
[abc someMethod]
#endif
// .....
}
Do not #define MYMACRO anywhere so that this code block is ignored by the compiler.
Hope that helps!

Setting a flag in compiler for NSLog not to show

Is there any particular flag which can be set to not display NSLog output in either debug or release?
Thanks.
One option might be to use a macro as a replacement for NSLog (if its easy for you to change things at this point). I like the prefix header file these guys use:
http://www.cimgf.com/2010/05/02/my-current-prefix-pch-file/
Basically their logging function is:
#ifdef DEBUG
#define DLog(...) NSLog(#"%s %#", __PRETTY_FUNCTION__, [NSString stringWithFormat:__VA_ARGS__])
#else
#define DLog(...) do { } while (0)
#endif
So if you are not in a DEBUG build, the logging macro becomes a no-op.
Generally, people write their own macro -- something like DebugLog -- for logs to be "compiled out":
#undef DebugLog
#ifdef DEBUG_MODE
#define DebugLog( s, ... ) NSLog( #"%#", [NSString stringWithFormat:(s), ##__VA_ARGS] )
#else
#define DebugLog( s, ... )
#endif
In Xcode, you can define macros for particular build configurations. For example, here I have DEBUG defined for Debug builds, and nothing for release builds.
Then to use this in the code, wrap your NSLog(...) statements in (or however you choose to use the macro, update:darren's method is quite good with this technique):
#ifdef DEBUG
NSLog(...);
#endif
Use the same mechanism for release configuration only logic.
You can use this ability if you have various number of build configurations, and you can define more than one macro if you want to enable/disable different levels of functionality for different build configurations.
Default flag with a new Xcode project is DEBUG for Debug and none for Release. So you will hide NSLog in Release this way:
#ifndef DEBUG
# define NSLog(...)
# define NSLogv(...)
#endif
Or if you want pretty custom logs as well (not using #ifdef here because no simple #elifdef):
#if DEBUG
# define NSLog(format, ...) NSLog((#"%s " format), __PRETTY_FUNCTION__, ##__VA_ARGS__)
# define NSLogv(format, ...) NSLog(#"%s %#", __PRETTY_FUNCTION__, [[NSString alloc] initWithFormat:format arguments:__VA_ARGS__])
#elif ADHOC
// default logs
#else// Release
# define NSLog(...)
# define NSLogv(...)
#endif
And if you want to override those macros and still log something sometimes, you can use:
(NSLog)(#"This log is always visible!");
Now, how to hide those as well? It would require you to #define NSLog NoLog and define NoLog as an extern function with an empty implementation like void NoLog(NSString *format, ...) {}. But it could be cleaner to avoid using (NSLog) altogether and instead use a function with a LogLevel enum:
typedef NS_ENUM(NSUInteger, LogLevel) {
LogLevelRelease,
LogLevelAdHoc,
LogLevelDeveloper,
};
void CustomLog(LogLevel level, NSString *format, ...) {
#if !DEBUG
if (LogLevel == LogLevelDeveloper)
return;
#if !ADHOC
if (LogLevel == LogLevelAdHoc)
return;
#endif
#endif
va_list ap;
va_start (ap, format);
NSLogv(format, ap);
va_end (ap);
}
The drawback of this CustomLog is that arguments get always evaluated, even in Release. So an optimal solution is multiple macros:
#define NSLog(format, ...) NSLog((#"%s " format), __PRETTY_FUNCTION__, ##__VA_ARGS__)
#if DEBUG
# define DebugLog(...) NSLog(__VA_ARGS__)
# define AdHocLog(...) NSLog(__VA_ARGS__)
# define ReleaseLog(...) NSLog(__VA_ARGS__)
#elif ADHOC
# define DebugLog(...)
# define AdHocLog(...) NSLog(__VA_ARGS__)
# define ReleaseLog(...) NSLog(__VA_ARGS__)
#else// Release
# define NSLogv(...)
# define DebugLog(...)
# define AdHocLog(...)
# define ReleaseLog(...) NSLog(__VA_ARGS__)
#endif
check for Debug mode using this macro
#ifdef DEBUG
//NSLog(#"XYZ");
#endif
Above NSLog will not get printed in Release mode
You can define a macro in the precompiled header (.pch) to disable NSLog:
#ifdef RELEASE
# define NSLog(...)
#endif
This disables NSLog in release builds.
Adding this b/c none of the answers seem to address warnings you may have (depending on project settings) with some of these approaches.
This is the only way I could find to suppress NSLog without getting any warnings. Otherwise I get a ton with the settings we use (warn on unused variables).
#undef NSLog
#define NSLog(fmt, ...) if (0) { printf("%s", [[NSString stringWithFormat:fmt, ##__VA_ARGS__] UTF8String]); }
Then all you need to do is put that in whatever pch file you use for your release builds or wherever you want to suppress the logs.
Credit to #Hot Licks for the example of how to make the variable "used".

How to redefine a macro using its previous definition

Suppose I have the following macro:
#define xxx(x) printf("%s\n",x);
Now in certain files I want to use an "enhanced" version of this macro without changing its name. The new version explores the functionality of the original version and does some more work.
#define xxx(x) do { xxx(x); yyy(x); } while(0)
This of course gives me redefition warning but why I get 'xxx' was not declared in this scope? How should I define it properly?
EDIT: according to this http://gcc.gnu.org/onlinedocs/gcc-3.3.6/cpp/Self_002dReferential-Macros.html it should be possible
Not possible. Macros can use other macros but they are using the definition available at expand time, not definition time. And macros in C and C++ can't be recursive, so the xxx in your new macro isn't expanded and is considered as a function.
Self-referential macros do not work at all:
http://gcc.gnu.org/onlinedocs/cpp/Self_002dReferential-Macros.html#Self_002dReferential-Macros
If you're working on C++ you can obtain the same results with template functions and namespaces:
template <typename T> void xxx( x ) {
printf( "%s\n", x );
}
namespace my_namespace {
template <typename T> void xxx( T x ) {
::xxx(x);
::yyy(x);
}
}
You won't be able to reuse the old definition of the macro, but you can undefine it and make the new definition. Hopefully it isn't too complicated to copy and paste.
#ifdef xxx
#undef xxx
#endif
#define xxx(x) printf("%s\n",x);
My recommendation is defining an xxx2 macro.
#define xxx2(x) do { xxx(x); yyy(x); } while(0);
If we know type of 'x' parameter in the 'xxx' macro, we can redefine macro by using it in a function and then define the 'xxx' macro as this function
Original definition for the 'xxx' macro:
#define xxx(x) printf("xxx %s\n",x);
In a certain file make enhanced version of the 'xxx' macro:
/* before redefining the "xxx" macro use it in function
* that will have enhanced version for "xxx"
*/
static inline void __body_xxx(const char *x)
{
xxx(x);
printf("enhanced version\n");
}
#undef xxx
#define xxx(x) __body_xxx(x)
From: https://gcc.gnu.org/onlinedocs/gcc/Push_002fPop-Macro-Pragmas.html
#define X 1
#pragma push_macro("X")
#undef X
#define X -1
#pragma pop_macro("X")
int x [X];
It is not exactly what you're asking for but it can help.
You can #undef a macro prior to giving it a new definition.
Example:
#ifdef xxx
#undef xxx
#endif
#define xxx(x) whatever
I never heard of (or seen) a recursive macro though. I don't think it is possible.
This answer doesn't answer your question exactly, but I feel like it does a good job at working the way you would intend to use your method (if it was possible).
The idea is for all of your file-specific macros that do actual work to have a unique name (for example LOG_GENERIC and LOG_SPECIFIC), and having the common token (in your case xxx) simply point to the currently appropriate macro.
Plus, using non-standard but widely available #pragma push_macro and #pragma pop_macro we can both modify the common xxx token and restore it to the previous version.
For example, imagine two header files, generic.hpp and specific.hpp, common token here being LOG:
// generic.hpp
#pragma once
#include <cstdio>
#define LOG_GENERIC(x) printf("INFO: " x "\n")
#define LOG LOG_GENERIC
void generic_fn(){LOG("generic");} // prints "INFO: generic\n"
// specific.hpp
#pragma once
#include "generic.hpp"
#define LOG_SPECIFIC(x) do {printf("<SPECIFIC> "); LOG_GENERIC(x);} while (0)
#pragma push_macro("LOG")
#undef LOG
#define LOG LOG_SPECIFIC
void specific_fn(){LOG("specific");} // prints "<SPECIFIC> INFO: specific\n"
#undef LOG
#pragma pop_macro("LOG")
By doing things this way we get the benefits of:
an easy mechanism to modify LOG in a restorable way via #pragma push_macro and #pragma pop_macro
being able to refer to certain LOG_* macros explicitly (LOG_SPECIFIC can use LOG_GENERIC)
we can't refer to LOG inside of LOG_SPECIFIC definition, we have to go through LOG_GENERIC
this is different to your question, but personally I am of the opinion that this is the better design, otherwise you gain the ability to allow macros above the LOG_SPECIFIC definition to affect it, just sounds like the wrong thing to do every time
Link to a github repository with the example above