【问题标题】:How can I make my iPhone App run both on 64 bit and 32 bit?如何让我的 iPhone 应用程序同时在 64 位和 32 位上运行?
【发布时间】:2013-11-17 02:03:32
【问题描述】:

我尝试在 64 位模式下运行时得到的确切错误是 Format specifies type 'int' but the argument has type 'long'

我可以通过将 %d 更改为 %ld 来修复此错误,但是当我在 32 位(正常)模式下运行应用程序时,我收到一条错误消息:Format specifies type 'long' but the argument has type 'int'

如何同时考虑 64 位和 32 位?我创建了一个 if(condition) 吗?

- (void)pickerView:(UIPickerView *)pickerView didSelectRow: (NSInteger)row inComponent:(NSInteger)component {
    // Handle the selection

    if(pickerView.tag == 1){
        start = row+1;
        [startButton setTitle:[NSString stringWithFormat:@"%d. %@", row+1, [stops objectForKey:[NSString stringWithFormat:@"%d", row+1]]] forState:UIControlStateNormal];
    }else if (pickerView.tag == 2){
        stop = row+1;
        [endButton setTitle:[NSString stringWithFormat:@"%d. %@", row+1, [stops objectForKey:[NSString stringWithFormat:@"%d", row+1]]] forState:UIControlStateNormal];
    }
}

【问题讨论】:

  • 请注意,long long 和 unsigned long long 在 32 位和 64 位处理器上都是 64 位。
  • long long 不会比普通的 int 占用更多的空间吗?这对于仅运行 32 位的 iPhone 是否实用?
  • 它将占用 64 位(8 字节),但除非您有数千位,否则又如何。请注意,这不是答案,只是信息,请参阅下面的答案。

标签: iphone objective-c xcode 64-bit 32bit-64bit


【解决方案1】:

不要使用NSIntegerNSUInteger 作为格式参数。而是将它们转换为(例如long long:

[NSString stringWithFormat:@"%lld", (long long)row+1]

【讨论】:

  • 我将它们投射到什么位置?我该如何选择?长长是最好的选择吗?
  • long long 是一个安全的选择。 clang 实际上有一个警告,建议将 NSInteger 转换为 long。
  • 最后一个问题...假设我决定让我的应用程序仅在 32 位上运行,因为它实际上并不需要更大的 64 位可变大小...新 iPhone 5S 会不会为我的应用降级到 32 位,或者它不会运行该应用?
  • 是的,两个问题。但无论如何,您只是暂时将其投射到(long long)
【解决方案2】:

如果您右键单击NSInteger,然后单击“转到定义”,您可以确切地看到#defined 并使用它作为骨架为%d/@ 设置类似的#define 987654325@ 匹配您的NSInteger


#if __LP64__
typedef long NSInteger;
#else
typedef int NSInteger;
#endif

这就是NSInteger 的工作原理。你可以做类似的事情:

#if __LP64__
#define FS_NSInt ld
#else
#define FS_NSInt d
#endif

然后只需使用FS_NSInt 作为NSIntegers 的格式说明符。 (仍然在它前面放一个%

【讨论】:

  • 所以我应该改变typedef int NSInteger;?
  • 不,你不能在 C 中重新定义 typedef。
  • 绝对不是。 NSInteger 是一个条件 typedef,在 32 位系统上使用 int,在 64 位系统上使用 long long。您可以查看typedefNSInteger(我目前不在Mac 上,或者我会为您编写)并将其用作骨架来编写类似条件#define 的格式说明符。
【解决方案3】:

来自Apple docs

类型说明符:

通常,在 32 位代码中,您使用 %d 说明符来格式化 int 函数中的值,例如 printf、NSAssert 和 NSLog,以及 stringWithFormat: 等方法。但是使用 NSInteger,它在 64 位 体系结构的大小相同,您需要使用 %ld 说明符。除非您像 64 位一样构建 32 位,否则这些 说明符在 32 位模式下生成编译器警告。为了避免这种情况 问题,您可以将值转换为 long 或 unsigned long,如 合适的。例如:

NSInteger i = 34;
printf("%ld\n", (long)i);

解决此问题的一种方法是使用 stdint.h 中的类型:
int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t

【讨论】:

  • 不会投射很长,占用比 int 更多的空间?如果 iPhone 只有 32 位,那么只有一个 int 不是更好吗?我有点困惑,因为这似乎是一个负面的好处......我一直被认为使用符合您需要的可变大小,长大于我的需要。这有意义吗?
  • 如果您永远不需要大于int 的数字,您应该只使用int 而不是NSInteger
  • 许多旧的“老生常谈”不再有效。规则 1:过早的优化是万恶之源。故事:我得到了一份工作,因为当被问及优化时,我首先回答了测量。
  • 我想我想说的是,用户担心通过转换为long 会浪费 32 位系统上的 RAM,但并不担心会浪费相同的 RAM使用NSInteger 的64 位系统(在64 位上将是long)。如果他担心并且他不需要int 无法容纳的数字,他可以使用int 并避免原始问题中的问题。
  • 或者他可以直接忽略大小/性能问题,除非有直接和证明相关的性能问题。
猜你喜欢
  • 2013-01-19
  • 2014-06-20
  • 2017-05-13
  • 1970-01-01
  • 2011-11-02
  • 2018-09-04
  • 2010-10-18
  • 2012-07-04
  • 1970-01-01
相关资源
最近更新 更多