Why type `nil` is not` id`, but `void *`

In this code

id (^block)(void) = ^(void) { return nil; }; 

I have this error

Incompatible block pointer types initializing 'id (^ __ strong) (void)' with an expression of type 'void * (^) (void)'

So I have to explicitly use nil to id type

 id (^block)(void) = ^(void) { return (id)nil; }; 

make the compiler happy. Buy why nil not an id type?

And for this code

 __typeof__(nil) dummy; dummy = [NSObject new]; 

Implicit conversion of the Objective-C pointer type 'NSObject *' to a C-pointer of type 'typeof (((void *) 0))' (aka 'void *') requires bridge casting

which says nil is (void *)0 , but not the same as NULL ? I, although nil should be (id)0 , and nil should be (Class)0 ?

I am using Xcode 4.6.2

Compiler: Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn)

+8
null objective-c objective-c-blocks
source share
3 answers

You use the return type for your block literal, but you don't need this.

The correct way to remove this error is to provide a return type for the block literal:

 id (^block)(void) = ^id{ return nil; }; 
+3
source share

When a block omits its return type, it now becomes the task of the compiler to infer the type of the block based on the returns in its body. But unfortunately, CLANG is looking for completely decomposed forms of return types, which leads to strange inconsistencies.

The most accessible example is array sorting. The comparator block type is NSComparisonResult(^)(id obj, id obj2) , but if you decide to omit the return type NSComparisonResult, the compiler gets a cry:

 NSArray *sortedArray = [array sortedArrayUsingComparator: ^(id obj, id obj2) { if (//...) return NSOrderedAscending; return NSOrderedDescending; }]; 

This block breaks up into a block of type int(^)(id obj, id obj2) , which the compiler considers incompatible (perhaps the enumerations are called only ints, so this should compile).

In the same way, id splits into objc_object* , which splits and continues until it reaches void* , or "any common pointer" (according to the C language specification). void * and id are definitely not the same type. To get around this, you must promise the compiler that the return type is really what it is, and the only way to do this is to quit.

LLVM 5.0 corrects this by making the compiler's conclusions more intelligent.

+3
source share

I don’t know why nil #define nil NULL in the Apple header (this is a fact, but I don’t know why it is not (id)0 , as expected), but I never had an error, mention in the latest version of Xcode and compiler.

I think that I remember at least a mistake in earlier versions of the outdated compiler that misinterpreted implicit casts like these in block return types and all.

Which compiler are you using? LLVM-GCC 4.2? or Apple LLVM 4.2? An older compiler? Check the build settings of your project. I recommend switching to Apple LLVM and checking if your problem resolves .

(in fact, LLVM-GCC is only used to upgrade from the old GCC to the new LLVM from some versions of Xcode now, but it is deprecated and should be removed in the next version of Xcode)

0
source share

All Articles