I have define VLog like this:
#define VLog(s, ...) NSLog(#"%#", [NSString stringWithFormat:(s), ##__VA_ARGS__])
I know VLog(#"hello,%d%#", 1, #"a"); __VA_ARGS__ is replaced with 1, #"a".
Whereas, VLog(#"hello"); __VA_ARGS__ is replaced with what?
and if I define VLog like this:
//delete ##
#define VLog(s, ...) NSLog(#"%#", [NSString stringWithFormat:(s), ##__VA_ARGS__])`
VLog(#"123"); is pointed out error.
In case of zero variable arguments, __VA_ARGS__ is replaced with nothing. ## is special in that it removes preceding , in that case, so compiler won't complain "expression needed after comma". A macro defined without ##, i.e. [NSString stringWithFormat:(s), __VA_ARGS__] will require additional arguments.
Related
I am looking for preprocessor directive to disable compiler warnings for desired block of code in MQL4.
I have some bitwise IFs and don't want to cast everything explicitly like:
if ( (bool)(flag & 0x00110101) ) {}
Instead I am looking for something like:
#nowarn
if ( flag & 0x00110101 ) {}
The method I am trying to call is;
- (void)addLogWithLevel:(MDCLogLevel)logLevel logContent:(NSString *)logContent, ...
{
va_list args;
va_start(args, logContent);
NSString *message = [[NSString alloc] initWithFormat:logContent
arguments:args];
va_end(args);
MDCLog *log = [MDCLog logWithContent:message content:logLevel];
[self.deviceLogs addObject:log];
}
I have defined the macro as;
#define MDCLogDebug(format, ...) [[MDCLogController sharedController] addLogWithLevel:MDCLogLevelDebug logContent:(__VA_ARGS__)];
I have tried various formats of this macro, but nothing seems to work.
If I am to call;
MDCLogDebug(#"Test:%#", #"Hey");
All I see in the console is;
Hey
Where am I going wrong? I'm new to using Variadic methods and my C isn't so great!
Actually, your problem is not really related to Objective-C directly, but to C itself, as macros are plain C preprocessor directives.
In a macro, __VA_ARGS__ represents the arguments that are placed instead of the ....
So in your call to MDCLogDebug(#"Test:%#", #"Hey"), the format argument is #"Test:%#" and __VA_ARGS__ represents the rest of the arguments afterwards, namely simply #"Hey" in your case.
If you want to pass both the #"Test:%#" and #"Hey" as arguments to logContent:, you have to explicitly tell it so, using:
#define MDCLogDebug(format, ...) [[MDCLogController sharedController] addLogWithLevel:MDCLogLevelDebug logContent:format, __VA_ARGS__]
Note: An even better solution would be to use the ## prefix before __VA_ARGS__ so that the comma won't be added if __VA_ARGS__ is empty (namely if you only pass a format argument but nothing afterwards, like MDCLogDebug(#"Foo")):
#define MDCLogDebug(format, ...) [[MDCLogController sharedController] \
addLogWithLevel:MDCLogLevelDebug \
logContent:format, ## __VA_ARGS__]
(Note: I use backslashes in this last macro definition above to allow the macro to be written on multiple lines, instead of writing it on one single big long line)
For more information, see the official GCC documentation about Variadic Macros here.
There are 3 (which I know) ways to suppress the "unused variable" warning. Any particular way is better than other ?
First
- (void)testString:(NSString *)testString
{
(void)testString;
}
Second
- (void)testString:(NSString *)__unused testString
{
}
Third
- (void)testString:(NSString *)testString
{
#pragma unused(testString)
}
This is the approach I use: cross platform macro for silencing unused variables warning
It allows you to use one macro for any platform (although the definitions may differ, depending on the compiler), so it's a very portable approach to express your intention to popular compilers for C based languages. On GCC and Clang, it is equivalent of wrapping your third example (#pragma unused(testString)) into a macro.
Using the example from the linked answer:
- (void)testString:(NSString *)testString
{
MONUnusedParameter(testString);
}
I've found this approach best for portability and clarity, in use with some pretty large C, C++, ObjC, and ObjC++ codebases.
If you are compiling with GCC, you can take advantage of attribute extensions to set the 'unused' attribute. Like this:
int somevar __attribute__((unused));
It also works for unused parameter warnings (-Wunused-parameter)
To make it shorter to write I am using this macro:
#define _U_ __attribute__((unused))
And declare like this:
int somevar _U_ ;
One way to do it is just to assign a variable pointlessly after it is declared For example:
int foo;
foo = 0;
This should suppress the unused variable warning. It is just a pointless assignment.
But otherwise I would agree with ouah, the first method is the most reliable, if you must choose from those three.
I understand how to use a preprocessor directive like this:
#if SOME_VARIABLE
// Do something
#else
// Do something else
#endif
But what if I only want to do something IF NOT SOME_VARIABLE.
Obviously I still could do this:
#if SOME_VARIABLE
#else
// Do something else
#endif
. . . leaving the if empty, But is there a way to do:
#if not SOME_VARIABLE
// Do something
#endif
Apple documentation here suggests not, but this seems like a very basic need.
Basically I want to do the preprocessor equivalent of:
if(!SOME_VARIABLE)(
{
// Do Something
}
you could try:
#if !(SOME_VARIABLE)
// Do something
#endif
Are you trying to check if something is defined or not?
If yes, you can try:
#ifndef SOME_VARIABLE
or
#if !defined(SOME_VARIABLE)
The Apple documentation (If - The C Preprocessor) is correct and this is the way that C pre-processor statements have been since the dawn of time. As per that same documentation all you can do is craft an expression that evaluates to either zero or a non-zero value and use that.
Meccan's answers is correct as TARGET_IPHONE_SIMULATOR is defined as TRUE or FALSE depending on the platform, so the expression will evaluate to either zero or a non-zero amount.
In general these macros (#if etc) are used for including or excluding things based on whether a symbol is defined or not. For that use case the pre-processor has #ifdef and #ifndef which covers what has historically been accepted as the most important cases.
Also given that the subject of these statements can only be other pre-processor defined symbols (via #define) then this limitation is reasonable.
I know this question has been asked several times, but mine is slightly different. Before closing this as duplicate, please read it fully.
There are many posts on stack overflow that says, "Personally, I hate MACROS, Don't use that shit". I've read all those and my case is different. I'm trying to define URLs used in a software (iOS app) using #define macros.
I agree that using const strings is a better practice than #define macros. But in an increasingly REST based API world that accepts query parameters as a part of URL, how can you still use const strings to represent a URL that changes?
Instead of http://api.myblog.com/posts?entryid=%#
a API Server that following REST principles would have
http://api.blog.com/posts/entries/[entryid]
In the former type, URL is http://api.myblog.com/posts for all entries and they don't change. A const string was possible.
In the latter type, URL changes with every entry and I use a Macro that expands to a full URL like this.
#define GET_ENTRY_URL(__MY_ENTRY_ID__) [NSString stringWithFormat:#"http://api.myblog.com/posts/entries/%#", __MY_ENTRY_ID__];
Are there any design flaws in my method?
Would like to know your inputs.
Thanks.
Looking from the perspective of the compiler, #define is a preprocessor directive (refer to the definition in c, http://en.wikipedia.org/wiki/C_preprocessor).
In this case, compiler might be doing the whole text replacement before compiling your codes.
e.g.: if you define:
#define GET_ENTRY_URL(__MY_ENTRY_ID__) [NSString stringWithFormat:#"http://api.myblog.com/posts/entries/%#", __MY_ENTRY_ID__];
it could be replacing every occurrences of GET_ENTRY_URL(x) with [NSString ..., x] in your codes. Potentially, instances might be created everywhere we use the macro if the implementation of objective-c is following this.
static const/variable seems to be a better way.
What I did in my app was define a const for the base path and a const for each specific path with substitution format codes inside the path when necessary.
NSString const *APIBasePath = #"http://api.mydomain.com";
NSString const *APIEntryPath = #"/entries/%d";
NSString const *APIUpdateEntryPath = #"/entries/%d/update";
I then construct the URL at runtime for each API as follows:
- (void)updateEntryNumber:(NSUInteger)entryNumber
{
NSString *updateEntryPath = [NSString stringWithFormat:APIUpdateEntryPath, entryNumber];
NSString *APIPath = [APIBasePath stringByAppendingPathComponent:updateEntryPath];
// do something
}