getting errors using macros in Objective-C - objective-c

I am new to Objective-C. I was trying out a sample program using macros and getting errors.
#import <Foundation/Foundation.h>
#define HELLO_WORLD #"Hello World"
#define a(x,y) ((x)+(y))
#define PRINTMAC(x,y)\
NSLog(#"%d",a((x),(y));\
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// insert code here...
//NSLog(#"%d",add(10,20));
PRINTMAC(13,72); //error:
[pool drain];
return 0;
} //error:
Error: expected ';' before '}' token

You appear to be missing a ) on the NSLog line (line 8).
Additionally, I'm not sure you need the final \ on that line, as the macro is not being carried on to a third line.
Finally, I don't think you need the ; on that line either as it, combined with the semi-colon when you invoke the macro on line 15 results in an empty statement (shouldn't be harmful, though).

Related

Why can I define a string as #"this is" #"one string"?

This seems to be a perfectly valid program:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSString* hey = #"hey"
#"there";
NSLog(#"%#",hey);
[pool drain];
return 0;
}
Compiling this in llvm gcc and apple llvm shows no warnings or errors. Why? It seems one should be warned about this, as I can only see this as chaos-inducing. Especially in a situation like this:
NSArray* a = [NSArray arrayWithObjects:#"one",
#"two,
#"three
#"four",
nil];
You'd expect four entries...but no! Tricky, huh? Is it because you may want to split your string definition across multiple lines?
It's a syntax for multi-line strings in Objective-C.
I cannot definitively answer why the language designer(s) designed it that way, but we can probably assume that they wanted the syntax for Objective-C strings to be analogous to the syntax for C strings.
That is, in C you can do the following for a multi-line string:
char *my_string = "Line 1 "
"Line 2";
And in Objective-C, you can do the following for a multi-line string:
NSString *my_string = #"Line1 "
#"Line2"; // The # on this line is optional.
(Code snippets adapted from https://stackoverflow.com/a/797351/25295)
Is it because you may want to split your string definition across multiple lines?
Yes. It is useful when you want to split the very long string for better code reading i.e. in NSLocalizedString key description.

CFArrayGetValueAtIndex not returning aything

I have an extremely simple code snippet to get the application support directory of a use. Problem is, it doesn't work! I get the values in a CFArrayRef (because I want to use C code since I will use this snippet in a C++ application later) and try to get the first string in there using CFArrayGetValueAtIndex(). I convert the returned void* to a char* using a C-style cast and attempt to output it using printf(), but nothing gets outputted! Can anyone explain why? I've looked online through the documentation for CFArray and tried to google the issue, but came up with nothing. Any help would be really appreciated!
Code:
#include <Foundation/Foundation.h>
#include <typeinfo>
int main (int argc, const char * argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
CFArrayRef array = \
(CFArrayRef)NSSearchPathForDirectoriesInDomains(
NSApplicationSupportDirectory,
NSUserDirectory,
YES);
char* string = (char*)CFArrayGetValueAtIndex(array, 0);
printf("string: %s\n", string);
[pool drain];
}
Why are you converting it to a char*? The resulting array from NSSearchPathForDirectoriesInDomains() contains CFStringRefs, not char*s.
Try using CFShow((CFTypeRef)CFArrayGetValueAtIndex(array, 0));

Weird error NSAssert

I can't figure out why I get
use of undeclared identifier _cmd did you mean rcmd
on the line where NSAssert is.
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int x = 10;
NSAssert(x > 11, #"x should be greater than %d", x);
[pool drain];
return 0;
}
Inside every Objective-c method there are two hidden variables id self and SEL _cmd
so
- (void)foo:(id)bar;
is really
void foo(id self, SEL _cmd, id bar) { ... }
and when you call
[someObject foo:#"hello world"]
it is actually
foo( someObject, #selector(foo), #"hello world")
If you cmd-click on NSAssert to jump to it's definition you will see that it is a macro that uses the hidden _cmd variable of the method you are calling it from. This means that if you are not inside an Objective-c method (perhaps you are in 'main'), therefore you don't have a _cmd argument, you cannot use NSAssert.
Instead you can use the alternative NSCAssert.
NSAssert is only meant to be used within Objective-C methods. Since main is a C function, use NSCAssert instead.
Try to replace
NSAssert(x > 11, [NSString stringWithFormat:#"x should be greater than %d", x]);
with
NSCAssert(x > 11, [NSString stringWithFormat:#"x should be greater than %d", x]);
You have to wrap your string in a NSString class if you want to use format parameters. That is because #"" is a default constructor for a plain NSString. The way it is written now gives a third parameter to the NSAssert function and messes with it.
NSAssert(x > 11, [NSString stringWithFormat:#"x should be greater than %d", x]);
TL;DR - stick with stray NSAssert() - don't try this in production
Original code
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int x = 10;
NSAssert(x > 11, #"x should be greater than %d", x);
[pool drain];
return 0;
}
Build failure
Compiling file hello.m ...
hello.m:9:5: error: use of undeclared identifier '_cmd'
NSAssert(x > 11, #"x should be greater than %d", x);
^
/usr/include/Foundation/NSException.h:450:32: note: expanded from macro 'NSAssert'
handleFailureInMethod: _cmd \
^
hello.m:9:5: error: use of undeclared identifier 'self'
/usr/include/Foundation/NSException.h:451:17: note: expanded from macro 'NSAssert'
object: self \
^
2 errors generated.
Based on explanation by #hooleyhoop #Robert and
id
self
SEL,
the following dirty hack may be applicable if I insist on using
NSAssert() instead of
NSCAssert()
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int x = 10;
// Dirty hack
SEL _cmd=NULL;
NSObject *self=NULL;
NSAssert(x > 11, #"x should be greater than %d", x);
[pool drain];
return 0;
}
Build & run
Compiling file hello.m ...
Linking tool hello ...
2021-03-04 21:25:58.035 hello[39049:39049] hello.m:13 Assertion failed in (null)(instance), method (null). x should be greater than 10
./obj/hello: Uncaught exception NSInternalInconsistencyException, reason: hello.m:13 Assertion failed in (null)(instance), method (null). x should be greater than 10
Hooray it works! But, alas, please stay away from it :)

simple code with EXC_BAD_ACCESS

I am new to the objective c and i write the code according to a reference book.
but something went wrong and I don't know why.
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
if (argc==1){
NSLog(#"you need to provide a file name");
return (1);
}
FILE *wordFile = fopen(argv[1], "r");
char word[100];
while(fgets(word , 100, wordFile)){
word[strlen(word)-1] = '\0';
NSLog(#"the length of the %s is %lu", word, strlen(word));
}
fclose(wordFile);
return 0;
}
the tool indicates that the while part went wrong, EXC_BAD_ACCESS.
Any idea?
It compiles and runs fine on my machine. But imagine you have an empty line in your file. Then strlen(word) will return zero. Hence word[strlen(word)-1] = '\0'; will try to set some memory which might not be valid since word[-1] might not be a valid memory cell, or a memory cell that you can legally access.
Oh, and by the way, it has nothing to do with objective-c. This is mostly (but for the NSLog call) pure ansi C.

CLANG Pass-By-Value Warning?

The following code compiles fine ...
int main (int argc, const char * argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// VARIABLES
MDD *MDD_structure;
NSString *mddFile = #"/Users/Gary/Code/Mdd/xTest.mdd";
NSFileHandle *inFile;
NSData *inBuffer;
int MDD_fCount;
int MDD_vCount;
// OPEN FILE ON DISK
inFile = [NSFileHandle fileHandleForReadingAtPath:mddFile];
if(inFile == nil) NSLog(#"FILE: Open ... ERROR");
else NSLog(#"FILE: Open ... OK");
// READ FRAME COUNT
inBuffer = [inFile readDataOfLength:sizeof(int)];
[inBuffer getBytes:&MDD_fCount length:sizeof(int)];
MDD_fCount = CFSwapInt32BigToHost(MDD_fCount);
NSLog(#"FC: %d", MDD_fCount);
But when I run it through the static analyzer "CLANG LLVM 1.0" I get the following ...
warning: Pass-by-value argument in function call is undefined.
MDD_fCount = CFSwapInt32BigToHost(MDD_fCount);
^ ~~~~~~~~~~
1 diagnostic generated.
Can anyone tell me what I am missing?
gary
You're getting an error because clang isn't convinced that simply passing the address of your variable to a function is the same as giving it a value. You could probably initialize MDD_fCount to 0 to start with to get rid of the error.
It means that you haven't initialized MDD_fCount. See this blog post and this other question for additional info.