foho
foho

Reputation: 779

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;
}

Upvotes: 49

Views: 6336

Answers (5)

user8243991
user8243991

Reputation:

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 :)

Upvotes: 0

hooleyhoop
hooleyhoop

Reputation: 9198

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.

Upvotes: 113

highlycaffeinated
highlycaffeinated

Reputation: 19867

NSAssert is only meant to be used within Objective-C methods. Since main is a C function, use NSCAssert instead.

Upvotes: 31

arun.s
arun.s

Reputation: 1528

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]);

Upvotes: 1

Alexander
Alexander

Reputation: 8147

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]);

Upvotes: 0

Related Questions