2

In LP64, the size of a long and the size of a long long are the same (Apple Docs, Unix Docs).

Is there any difference then, when limiting yourself to the understanding that you're running on an LP64 system (as XCode appears to when compiling for 64 bit), between a long and a long long? Is there any performance reason to use a long instead of a long long if your goal is a 64 bit integral?

Here's why I ask. In Objective C on Xcode, NSString's format (like printf) and NSNumber both use data types like int, long, long long and their unsigned variants when converting numbers and text and not specific bit length numbers like int16_t, int32. and int64_t. This would make it difficult to program things that require a certain minimum size (i.e. networking or currency applications) or times when you want to store specifically sized data into an NSNumber without typecasting.

Is it safe, limiting to any Intel Mac OS or iOS device, to use int for int32_t and long long for int64_t when interacting with things like NSString's format functions and NSNumber?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Erroneous
  • 535
  • 4
  • 12

2 Answers2

2

Is it safe, limiting to any Intel Mac OS or iOS device, to use int for int32_t and long long for int64_t when interacting with things like NSString's format functions and NSNumber?

According to the ILP32 & LP64 conventions yes, but you should really document that you are relying on these sizes.

One way to do that is to use a clever macro that originated (as I understand) in the Linux kernel:

#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))

This macro will generate a compile time error if its condition argument is true, as in that case it attempts to determine the size of a negative-sized array. You can use it in the following simple function:

static __attribute__((unused)) void _compile_time_use_only_()
{
   BUILD_BUG_ON( (sizeof(int) != 4) );
   BUILD_BUG_ON( (sizeof(long long) != 8) );
}

Add that to your code and if you attempt to compile on any system where int is not 32-bits or long long is not 64-bits then you'll get a compile time error. There is essentially zero-cost at runtime (just a few bytes for the unused function).

Make sure you comment the function stating what it does!

You can of course assert the size of other types the same way.

HTH

CRD
  • 52,522
  • 5
  • 70
  • 86
  • I'm going to mark this as correct because it did answer at least part of the question. It would be nice to know if there is any difference between an int and a long in a 32 bit system or a long and a long long in a 64 bit system. To add to the answer, you could of course put this inside an `#ifndef NDEBUG` so that it'll not take any resources when you compile for release. – Erroneous Jan 08 '16 at 20:20
  • @Erroneous - under ILP32 `int` and `long` are both 32-bit integers, there is no practical difference between them, exactly the same code will be compiled for the two types, they are effectively just aliases of each other. Similarly for any other integer types which are the same size. HTH – CRD Jan 09 '16 at 08:47
  • Why are you double-`()`-wrapping your checks when the `BUILD_BUG_ON()` macro itself (correctly) `()`-wraps the condition _(such that it preprocesses into `…((sizeof(int) != 4))…`)_?  Is there a special reason to do this?  Or is this just a bad habit you picked up from using macros that are poorly written and don't `()`-wrap their args? – Slipp D. Thompson Jan 30 '17 at 22:03
  • @SlippD.Thompson - it is just subconscious defensive macro programming, always assume a macro will bite ;-) – CRD Jan 31 '17 at 00:40
  • Ah, okay. I guess I've been taught and adhere to “make sure you understand the functionality you're using, and if there's a bug in that functionality then fix it or write a wrapper around it.” – Slipp D. Thompson Jan 31 '17 at 00:42
0

Use either NSInteger or int64_t. NSInteger = fastest type with at least 32 bits, and compatible with sizes of arrays etc. int64_t = exactly 64 bit. This will also make the move to Swift easier.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
  • 1
    `NSInteger` is not "fastest type with at least 32 bits". It's [simply defined](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Cocoa64BitGuide/64BitChangesCocoa/64BitChangesCocoa.html#//apple_ref/doc/uid/TP40004247-CH4-SW11) as equivalent to `long` in 64-bit and `int` in 32-bit. – Ken Thomases Jan 05 '16 at 00:33
  • @KenThomases But on most architectures, the faster of a 32-bit int and a 64-bit int is the one that matches the CPU's register size… which is 32 bits on 32-bit and 64 bits on 64-bit.  _Do you have any documentation that states that `NSInteger` **wasn't** chosen to be these sizes because of register size?_  There's no doubt that a number of considerations went into the decisions behind this functionality, and without a counter-argument it's likely that register size was one of those considerations. – Slipp D. Thompson Jan 30 '17 at 22:09
  • @Slipp: At the top of the document I linked, there are reasons given: "required for 64-bit addressing", "consistency, ease of porting, and 'impedance match'". [Here](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/64bitPorting/HighLevelAPIs/HighLevelAPIs.html#//apple_ref/doc/uid/TP40001064-CH224-SW1), more reasons: future expansion, pointer size, large data set support. Never a mention of register size. `NSInteger` had to remain `int` for 32-bit apps for binary compatibility. For 64-bit, the capacity, not speed, was the motivation. – Ken Thomases Jan 31 '17 at 01:49
  • Also, stdint.h defines `int_fast32_t` as `int32_t`, regardless of target architecture. If 64-bit were actually faster for x86-64, it would use `int64_t` instead. – Ken Thomases Jan 31 '17 at 01:51
  • @KenThomases “Required for 64-bit addressing” and “impedance match” are technical specifics for the benefit of speed (among others). “Pointer size” is likewise an analogue for register size— _the “##-bit” description of CPUs is literally the register/pointer size (beyond a few examples of esoteric decades-old CPUs)._ – Slipp D. Thompson Jan 31 '17 at 19:16
  • Um, yes, of course, the *size* is relevant, but not because the CPU handles them more quickly. It's because it's needed to handle values larger than can fit in 32 bits. – Ken Thomases Feb 01 '17 at 03:37