Removing NSInteger warning using __LINE__ - objective-c

I have a log function:
#define LOGERROR(err) if(err) { \
LOGTRACE(#"[NSError] %s (%d): (%d:%#) Reason: %#", \
__PRETTY_FUNCTION__, \
__LINE__, \
err.code, \
err.domain, \
err.localizedDescription) \
}
When I call it with
LOGERROR(playerItem.error);
I get a warning: "NSInteger should not be used as a format argument, add an explicit cast to long".
Xcode's autofix inserts %ld before LOGERROR, which is wrong.
I think this warning comes from the use of __LINE__, which according to https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html returns an int.
How can I remove the warning from this call?

Just to formalize the answer I gave in a comment:
The compiler is complaining about the use of err.code, which returns an NSInteger. Cast it to a long: (long)(err.code), and then use %ld in the format string.

Related

'VA_ARGS', an invalid preprocessing token in macros Obj-C

I use following technique to manage my logs. I print logs to asl_log and before, regards to flag [DebugManager shared] isDebugging I want to send log line to other class (method addLogEvent)
#if !defined(TheLog)
#define TheLog(fmt, ...) { \
if ([[DebugManager shared] isDebugging]) \
addLogEvent(__PRETTY_FUNCTION__,fmt,##__VA_ARGS__); \
}
#endif
#define __AF_MAKE_LOG_FUNCTION(LEVEL, NAME) \
inline void NAME(NSString *format, ...)\
{ \
TheLog(__PRETTY_FUNCTION__,format,##__VA_ARGS__);\
va_list arg_list; \
va_start(arg_list, format); \
NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:arg_list]; \
asl_add_log_file(NULL, STDERR_FILENO); \
asl_log(NULL, NULL, (LEVEL), "PREFIX: %s", [formattedString UTF8String]); \
va_end(arg_list); \
}
// Something has failed.
__AF_MAKE_LOG_FUNCTION(ASL_LEVEL_ERR, AFLogError)
// Something is amiss and might fail if not corrected.
__AF_MAKE_LOG_FUNCTION(ASL_LEVEL_WARNING, AFLogWarning)
// The lowest priority for user log
__AF_MAKE_LOG_FUNCTION(ASL_LEVEL_INFO, AFLogDebug)
I map log level with __AF_MAKE_LOG_FUNCTION(LEVEL, NAME) and I need to call TheLog(__PRETTY_FUNCTION__,format,##__VA_ARGS__);\ from inline void NAME(NSString *format, ...)
I get an error:
Pasting formed ',__VA_ARGS__', an invalid preprocessing token
How can I fetch ,__VA_ARGS__ and __PRETTY_FUNCTION__?
This line:
TheLog(__PRETTY_FUNCTION__,format,##__VA_ARGS__);\
is part of the definition of this macro:
#define __AF_MAKE_LOG_FUNCTION(LEVEL, NAME) \
Note that that macro does not take a variable argument list. Therefore, there's no __VA_ARGS__ defined within its definition.
The fact that the function being defined by an instantiation of __AF_MAKE_LOG_FUNCTION — the inline void NAME() — takes a variable argument list isn't relevant. If that function wants to pass the variable argument list along to another function, it needs to do it using the stdarg functionality, as it does for -[NSString initWithFormat:arguments:], but that doesn't work for your TheLog macro, because it's not designed to accept a va_list.
You can't do what you're attempting. Your TheLog macro is incompatible with how you're trying to use it. You would need to design an alternative version, such as:
#define TheLogv(fmt, args) { \
if ([[DebugManager shared] isDebugging]) \
addLogEventv(__PRETTY_FUNCTION__,fmt,args); \
}
Note that this would, in turn, require the existence of a function addLogEventv() which accepts a va_list instead of an actual variable argument list. Within the body of the function being defined by __AF_MAKE_LOG_FUNCTION, you'd have to start and end the list twice, once around each time you pass it to another function, because each function will "consume" it:
#define __AF_MAKE_LOG_FUNCTION(LEVEL, NAME) \
inline void NAME(NSString *format, ...)\
{ \
va_list arg_list; \
va_start(arg_list, format); \
TheLogv(__PRETTY_FUNCTION__,format,arg_list);\
va_end(arg_list); \
va_start(arg_list, format); \
NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:arg_list]; \
asl_add_log_file(NULL, STDERR_FILENO); \
asl_log(NULL, NULL, (LEVEL), "PREFIX: %s", [formattedString UTF8String]); \
va_end(arg_list); \
}
You could also change your TheLog() macro to take an NSString* and simply pass in the formattedString that's already being created.

Random Number Objective-C (linux)

Now, I know that this is a simple question for MacOS, but when I compile a code with 'arc4random % n' in it, I just get an error log in Terminal saying:
main.m:9: error: ‘arc4random’ undeclared (first use in this function)
main.m:9: error: (Each undeclared identifier is reported only once
main.m:9: error: for each function it appears in.)
and I use:
gcc `gnustep-config --objc-flags` -lgnustep-base main.m -o main
to compile it
and here's my code (if it helps) :
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int number, guess;
number = arc4random() % 101;
while (!guess == number) {
NSLog (#"Please guess a number between 1 and 100");
scanf ("%i", &guess);
if (guess < number) {
NSLog (#"Sorry, guessed too low!");
}
else if (guess > number) {
NSLog (#"Sorry, guessed too high!");
}
}
NSLog (#"You guessed correct!");
[pool drain];
return 0;
}
You may consider using clang instead of gcc
Use
clang -fno-objc-arc main.m -framework Foundation -o main
Also I'd use arc4random_uniform(101) instead of arc4random() % 101, since the former is bias free.
A few things:
Your use of >> and <<, these are not valid comparison operators. This will compile, but not perform what you expect. You either need to use > (greater than), >= (greater than or equals), < (less than) or <= (less than or equals).
Your compile error is due to your use of arc4random. This is a function, but you've not used it as such. You need to change your line to
number = arc4random() % 101;
Not 100% sure on this, but %i in your scanf looks like it should be %d

__VA_ARGS__ Macro expansion

I'm trying to get my macro to work like NSLog() which accepts variable arguments. Code below causes parse issues.
What is the correct way to define this?
#define TF_CHECKPOINT(f, ...) \
do { \
NSString *s = [[NSString alloc] initWithFormat:f arguments:__VA_ARGS__] autorelease]; \
[TestFlight passCheckpoint:[NSString stringWithFormat:#"%#: %#", [self class], s]]; \
} while (0)
You forgot the opening bracket for the autorelease message.
Moreover -[NSString initWithFormat:arguments:] expects a va_list argument, whereas __VA_ARGS__ is replaced by all the passed arguments. Here, you need to use -[NSString initWithFormat:] or +[NSString stringWithFormat:].
Finally, you may prefix __VA_ARGS__ with ##. By doing so, the preceding comma is deleted when there is no argument.
Try this:
#define TF_CHECKPOINT(f, ...) \
do { \
NSString *s = [NSString stringWithFormat:(f), ##__VA_ARGS__]; \
[TestFlight passCheckpoint:[NSString stringWithFormat:#"%#: %#", [self class], s]]; \
} while (0)

Objective-C macro to return a string with the function and the line number while accepting a string with a variable number of arguments?

I've found a bunch of macro variations on how to use NSLog as a basis and adding PRETTY_FUNC and LINE but all the variations of those macros simply output the result to the console.
I'd like to have a macro that can take a format with a variable number of arguments, add the name of the method and line number where it was called and then return an NSString but so far, the compiler always complains where I call it. My latest version is as follow:
#define FileLog(format, ...) {\
return [NSString stringWithFormat:#"\n %s [Line %d] \n %#",
__PRETTY_FUNCTION__,
__LINE__,
[NSString stringWithFormat:(format), ##__VA_ARGS__]];\
}
Each time I call it from my code, the compiler generates one of those errors:
error: expected expression before '{' token
I don't want to write a log class or use a framework for that. There must be a way to do that with a macro? Anyone?
Thanks in advance!
This is entirely possible with a macro, I think you just need a little more background on them.
First, macros are not functions, so the braces are unnecessary (and, in fact, are the cause of your error). A macro is really a fairly dumb "copy/paste" that is automated by the preprocessor, using syntax that it understands.
In order to define a macro that spans multiple lines and creates an NSString "in place", you have to escape the newlines with backslashes, like so:
#define FileLog(format, ...) \
[NSString stringWithFormat:#"\n %s [Line %d] \n %#", \
__PRETTY_FUNCTION__, \
__LINE__, \
[NSString stringWithFormat:format, ##__VA_ARGS__]]
Macros do not "return" like a function does, because, as I mentioned, they are merely a way to "copy/paste" text.
You can use it like so:
int num = 42;
NSLog(#"%#", FileLog(#"some number: %d", num));
If you were to look at the preprocessor output (the file that the preprocessor creates before compilation), the above example would expand to something like:
NSLog(#"%#", [NSString stringWithFormat:#"\n %s [Line %d] \n %#", __PRETTY_FUNCTION__, __LINE__, [NSString stringWithFormat:#"some number: %d", num]]);
Try this....
Create an include file
#define LOG_NOLOG_LEVEL 0
#define LOG_ERROR_LEVEL 1
#define LOG_WARN_LEVEL 2
#define LOG_INFO_LEVEL 3
#define LOG_DEBUG_LEVEL 4
#if LOG_HELPER_LEVEL >= LOG_DEBUG_LEVEL
#define LOGDEBUG(...) {[LogHelper log:[NSString stringWithFormat:__VA_ARGS__]];}
#else
#define LOGDEBUG(...)
#endif
#if LOG_HELPER_LEVEL >= LOG_INFO_LEVEL
#define LOGINFO(...) {[LogHelper log:[NSString stringWithFormat:__VA_ARGS__]];}
#else
#define LOGINFO(...)
#endif
#if LOG_HELPER_LEVEL >= LOG_WARN_LEVEL
#define LOGWARN(...) {[LogHelper log:[NSString stringWithFormat:__VA_ARGS__]];}
#else
#define LOGWARN(...)
#endif
#if LOG_HELPER_LEVEL >= LOG_ERROR_LEVEL
#define LOGERROR(...) {[LogHelper log:[NSString stringWithFormat:__VA_ARGS__]];}
#else
#define LOGERROR(...)
#endif
Then create a simple class LogHelper with a single class method as follows....
+ (void) log:(NSString *)message
{
fputs([message cStringUsingEncoding:NSUTF8StringEncoding], stderr);
}
Then in your code, you can put calls like...
LOGDEBUG(#"%s - %d Redirect response received\n%#",__FILE__,
__LINE__,[redirectRequest dumpInfo]);
You can set the LOG_HELPER_LEVEL to the level of logging you want to produce. If you set the level at say LOG_WARN_LEVEL, then no code will be included in your app for INFO or DEBUG levels, so it's easy to package your app up for release.
Hope this helps...
From Viraj Thenuwara, who was my iOS Senior developer who trained me :-)
This macro is much more simpler in its definition and also its usage, than the things mentioned above.
#define debug 1
#if debug
#define AppLog(fmt, ...) NSLog((#"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#define AppLog(...)
#endif
And it's usage is as follows:
NSString *url = #"http://google.com";
AppLog(#"url %# and id %d", url, 5);
This AppLog line will print out it's given content only if the debug constant is equal to 1. At the Production time or in anytime you don't want to print the log lines you can disable it by turning that 1 into 0.
And it's console out put will be seen as follows:
Hope this will be helpful to someone else!
Cheers!

#define macros and xcode warning and lack of code hinting

I wrote up some small macros to help in setting application-wide font styles, colors and gradients. The issue is that xcode is throwing warnings whenever I use the color or font defined in the macro. Is there any way to get xcode to validate the macro, and hopefully get code hinting as well?
#define HEX_COLOR(colorname, hexcolor) \
\
#implementation UIColor(Style##colorname) \
\
+ (UIColor*) colorname \
{ \
static UIColor * staticColor = nil; \
if(! staticColor) { \
float red = ((hexcolor & 0xFF0000) >> 16)/255.0; \
float green = ((hexcolor & 0xFF00) >> 8)/255.0; \
float blue = (hexcolor & 0xFF)/255.0; \
float alpha = (hexcolor >> 24)/255.0; \
\
staticColor = [[UIColor colorWithRed:red \
green:green \
blue:blue \
alpha:alpha] retain]; \
} \
return staticColor; \
} \
#end
In my app delegate i set the application-wide fonts and colors like this:
HEX_COLOR(specialGreenColor, 0x66BAD455);
.....
This line throws the warning that the property might not exist.
[[UIColor specialGreenColor] set];
Also I do not want to lessen the error reporting in xcode as not seeing warning is a backwards step. I just would like to find a way to regiester the marco with xcode.
If you want to define constants, you should use #define like so:
#define COLOUR_NAME 0x66BAD455
Then, the preprocessor will go through your file and replace all instances of COLOUR_NAME verbatim with 0x66BAD455.
There are arguably better ways to define application-wide constants though.
Edit: there's also this nice post which seems to provide a better implementation of what you're going for. You can define the macro and then define your colour constants using the question linked above.
Code hinting for the marco works in xCode 4.2