I'm not experienced in C, so I'm not comfortable with this statement in this C / objective-C project.
#define CBLog(...) NSLog(#"%s [%ld]: %#", basename(__FILE__), __LINE__, [NSString stringWithFormat:__VA_ARGS__])
Questions:
the 3 dots (...) are used to indicate CBLog() is a method with parameters ? What do they mean ?
%ld stands for line format ? what's the d in %ld for ?
FILE , LINE and VA_ARGS are default replacement tokens for the C debugger ?
thanks
The ... means the macro accepts any number of arguments.
%ld is a string formatter meaning 'long decimal', where decimal really means integer.
__FILE__ expands to the current file name
__LINE__ expands to the current line number
__VA_ARGS__ expands to the arguments passed to the macro.
The debugger has nothing to do with it. All of this is the preprocessor, except %ld which is string formatting.
... means that any number of arguments can be given.
%ld means signed long, though it's a bit strange as I've never seen signed line numbers.
__FILE__ is the current source file's filename. __LINE__ is the current line number. __VA_ARGS__ are the arguments given to the macro.
Related
I created a special console log function macro. It works successfully except when there's a comma in the parameter, even if it's part of another expression, i.e. not another argument. I think it's due to the fact that macros are expanded at the pre-processing stage, so the semantic analysis hasn't occurred yet to understand that the comma is not another argument. Here is what I mean:
#define FANCY_LOG(message) [MyLogger logDebug:message withClassAndMethodName: __PRETTY_FUNCTION__ lineNumber: __LINE__];
+(BOOL)logDebug:(NSString *)message withClassAndMethodName:(const char *)name lineNumber:(int)lineNumber;
These work:
FANCY_LOG(#"Hello world");
FANCY_LOG([NSString stringWithFormat:#"Hello!"]);
This does not work:
FANCY_LOG([NSString stringWithFormat:#"Hello %#!", planet]);
Although the comma obviously is part of the NSString expression, the macro interprets it as another argument, I get the following error:
Too many arguments provided to function-like macro invocation
Here's what I have tried unsuccessfully (and variants of these):
#define FANCY_LOG(...) [MyLogger logDebug:##__VA_ARGS___ withClassAndMethodName: __PRETTY_FUNCTION__ lineNumber: __LINE__];
#define FANCY_LOG(message) [MyLogger logDebug:#message withClassAndMethodName: __PRETTY_FUNCTION__ lineNumber: __LINE__];
You are doing that wrong. First of all there are lots of great ready solutions so you do not have reinvent the wheel (don't remember for sure but I think CocoaLumberjack is best).
And your logger can look like this (I've got rusty with Objective C):
+(void) function:(char *)methodName
inLine:(int)line
logs:(NSString *)format, ...;
...
#define FANCY_LOG(...) [MyLogger function: __PRETTY_FUNCTION__ \
inLine: __LINE__ \
logs: __VA_ARGS__]
// then usage:
FANCY_LOG(#"Hello %#!", planet);
And also, why is it not necessary for, eg:
printf ("abc")
NSLog takes an NSString as argument. #"abc" denotes an NSString because of the # sign, so that is a valid argument for NSLog. printf is a normal C function that takes a C string, which is simply created using "".
UPDATE:
NSLog(#"%#",dictionary)
Tells the compiler that i got string to fulfill the requirement of string argument.
Update: Sorry I was supposed to write the "NSLog" instead of printf. my mistake!
Because it requires NSString. Adding #declares value as type of NSObject (simplification).
#define CLog( s, ... ) NSLog( #"%#", [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#define PO(x) CLog(##x ": %#", x)
Then I do:
NSString * hello =[NSString stringWithFormat:#"%#, %#",theCatalogData.id,#(theCatalogData.images.count)];
PO(hello);
Works
Of course, a shortened version of this is simply:
PO([NSString stringWithFormat:#"%#, %#",theCatalogData.id,#(theCatalogData.images.count)]);
That doesn't work. I wonder why.
No emergency. No problem. The longer equivalent works anyway. I just want to understand how the compiler parses the macro to see why things don't work.
Since the pre-processor does not really understand syntax in itself, macro parameters containing commas will cause problems.
In the second case, since the parameter contains two commas outside of quotes, the compiler thinks the macro is getting 3 parameters instead of one, and since the macro takes only one parameter, the compiler will complain.
A simplified test case similar to your second case;
#define TEST(a,b,c) a
TEST([d e:#"%#, %#", f, g])
will expand to;
[d e:#"%#, %#"
which shows that the a parameter only contains all characters up to the first un-quoted comma.
In your case, you define the TEST macro to take one parameter and since the pre-processor considers it 3, compilation will fail.
UIAlertView *message = [[UIAlertView alloc] initWithTitle:[[LanguageManager sharedLanguageManager] get:#"Notice"]
message:[NSString stringWithFormat:[[LanguageManager sharedLanguageManager] get:#"Notice_Text"]]
delegate:nil
cancelButtonTitle:[[LanguageManager sharedLanguageManager] get:#"Close"]
otherButtonTitles:nil];
Hi, let me explain my codes above. Basically it calls up an UIAlertView with data read from a .plist via my LanguageManager singleton class. The LanguageManager get function basically returns a NSString*. I know I should use the NSLocalizedString class but I had been using this class for a while now, so I had decided to stick to it.
My problem lies with the "message:" parameter. The string I am trying to read contains formatting characters like \n but it does not output correctly and appears as \n instead of a line break when printed. I also get the "Format string is not a string literal" warning. Other parts of the app using similar method to return a string which contains %d or %f works correctly though, just the '\n' character not working.
Does anyone have any idea how I may overcome this?
"\n" is not a "formatting character": the compiler translates it to the appropiate code; the string NEVER contains the "\" and "n" characters.
Thus, if you string comes from a source that is NOT compiled by a (Objective-)C(++) compiler, "\n" will be just the two characters. Nothing will turn them into a newline, unless you do it yourself with something like
NewString=[MyString stringByReplacingOccurrencesOfString:#"\\n" withString:#"\n"];
Note the two different strings: in the first case, "\" prevents the compiler from doing the \n -> newline conversion, while the second string will be an actual newline.
The warning about a non-literal format string is somewhat pointless; I've yet to find a good way to get rid of that one (for now, I just disable it entirely, using -Wno-format-nonliteral on clang++ >= 4.0).
Is there anyway we can take input from command line in Objective-C, the way we can take in C/C++?
int inputVariableName;
cin >> inputVariableName;
scanf("%i", userInput);
just as you would in c
To get Objective-C objects from the input, simple convert them after reading them in:
NSNumber * number = [nsnumber numberwithint:useriput];
Sure. Compile your code as Objective-C++.
This is typically as easy as renaming the file from having a .m suffix to a .mm suffix.
Documentation is included with the Xcode tools as to the details of Objective-C++.
As bbum mentioned, you can use NSFileHandle to get access to stdin. If you just want to read the command line arguments, you can get them from [[NSProcessInfo processInfo] arguments]. It's also worthwhile to know what else NSProcessInfo can tell you.
Command line input with spaces
char textInput[1000];
scanf("%[^\n]%*c", textInput);
NSString* userInput = [NSString stringWithUTF8String:textInput];
NSLog(#"\n%#\n%#", #"Hello, World.", userInput);
Input text with white spaces, 1000 is input character limit.