9

After updating Xcode to version 5.1, I had a warning that told me I had defined a constant that I wasn't using. Its definition looked like this:

static NSInteger const ABCMyInteger = 3;

I was happy to see that it got marked, because I thought this meant that the compiler was now able to check for unused constants in addition local to variables.

I refactored some more, making three NSString constants obsolete. All three were defined very similarly to the NSInteger from above:

static NSString *const ABCMyString = @"ABCMyString";

To my surprise, however, these do not get marked as "unused", though I know for sure that they aren't used anymore.

Can someone explain why an NSInteger does get noticed by the compiler as unused, but an NSString does not?

Scott Berrevoets
  • 16,921
  • 6
  • 59
  • 80
  • The only difference I can spot is that NSInteger is a primitive data type, whereas NSString is a class. Maybe (but surprisingly) the compiler generate warnings for primitive types only. I suggest you to try with other types (float, char, NSArray, UIView) to verify if I am right or not (I haven't updated to 5.1 yet, so I can't try myself). – Antonio Mar 18 '14 at 21:47
  • @Antonio: Looks like you're right, it only works for primitives. `float` triggered it, `NSArray` did not. My question still remains: why is the compiler not able to do this with objects? – Scott Berrevoets Mar 18 '14 at 21:58
  • As a side note, other IDEs (at least AppCode) are able to warn about unused NSString constants, but they rely on some additional code inspection, not the compiler warnings – Michał Ciuba Mar 20 '14 at 21:55
  • Also, if you put `static NSString *const ABCMyString = @"ABCMyString";` inside a method (that is, not in a global scope) XCode actually warns you about "unused variable" :) interesting – Michał Ciuba Mar 20 '14 at 22:13
  • 1
    Adding an `extern static NSInteger const ABCMyInteger;` in an H file should remove the warning. – Léo Natan Mar 20 '14 at 22:43
  • @LeoNatan: That gives me "Cannot combine with previous 'extern' declaration'. That would also make the constant public which is not always desirable. – Scott Berrevoets Mar 21 '14 at 16:04
  • @ScottBerrevoets I may have messed up the syntax, but it's just the idea. But yes, my post is about public constants (not really related to your question). Why the compiler does not warn about unused objects is good question. Likely a bug or a known limitation. – Léo Natan Mar 21 '14 at 16:27
  • Looks like the CLANG folks already know this is a limitation. [rdar://10777111](https://llvm.org/viewvc/llvm-project?view=revision&revision=161291) – CodaFi Mar 23 '14 at 03:42

2 Answers2

2

A primitive variable is just a memory block allocated in a static memory part and initialized by the compiler. The string object, however, is a variable initialized at runtime (in startup, probably), so the compiler adds an implicit call to the constructor and uses the variable as a parameter for that call. So the variable is being used.

The _unused item of the structure is IMHO not a directive, but just a member variable, probably it is added for better alignment (fills the object size to a round size).

CiaPan
  • 9,381
  • 2
  • 21
  • 35
1

The definition of an NSString literal at compile time rely on the use of the NSSimpleCString meta class. This class looks something like this:

@interface NSSimpleCString : NSString {
@package
    char *bytes;
    int numBytes;
#if __LP64__
    int _unused;
#endif
}
@end

@interface NSConstantString : NSSimpleCString
@end

The addition of the _unused flag make me believe that further down the implementation of NSSimpleCString the code will instruct the compiler to silence those warnings with __unused.
You can try yourself by prepending your integer or float constant with __unused like:

__unused static const NSInteger ABCMyInteger = 3;

For a more in depth explanation read the article on literals by Mike Ash

cescofry
  • 3,706
  • 3
  • 26
  • 22
  • Thanks, very helpful! For some reason, the `__unused` directive is implicitly used on `NSConstantString` (or one of its subclasses). The `_unused` ivar may have to do with it, but to me it's unclear how it plays a role in this situation, especially since it depends on a 64-bit architecture, and the warning is also there when I build for 32-bit only. – Scott Berrevoets Mar 24 '14 at 15:04
  • You are right I should have made more that `_unused` is not the compiler flag, but it is flag likely to trigger it dipper in the code implementation of `NSSimpleCString` and so likely `NSConstantString` – cescofry Mar 24 '14 at 15:08
  • Quite possibly. I would accept that, if it wasn't conditionally compiled with `__LP64__`. That instance variable doesn't exist on 32-bit platforms (unless it is defined privately there, but I don't see why they would do that), but the compiler doesn't give the warning on 32-bit either. – Scott Berrevoets Mar 24 '14 at 15:24
  • I am not 100% sure of this, but I think the hardware you chose for your target doesn't count, what counts is the precompiler defines. There are several reports around about weird responses of the use of `__LP64__` (first comment here http://stackoverflow.com/questions/18861046/how-to-determine-if-compiling-for-64-bit-ios-in-xcode). Also if you try to check for the precompiler #define on your machine with `cpp -dM /dev/null |grep __LP64__` you will see that `__LP64__` is there no matter what. – cescofry Mar 25 '14 at 10:49