【问题标题】:Variably modified array at file scope文件范围内可变修改的数组
【发布时间】:2010-12-15 07:37:07
【问题描述】:

我想在我的“.m”文件的顶层创建一个用于整个 Objective-C 实现文件的常量静态数组:

static const int NUM_TYPES = 4;
static int types[NUM_TYPES] = { 
  1,
  2, 
  3, 
  4 };

我打算稍后在文件中使用NUM_TYPES,所以我想把它放在一个变量中。

但是,当我这样做时,我得到了错误

“文件范围内可变修改的‘类型’”

我认为这可能与作为变量的数组大小有关(当我将整数文字放在那里时,我没有收到此消息,例如 static int types[4])。

我想解决这个问题,但也许我做错了...我在这里有 2 个目标:

  1. 拥有一个可在整个文件中访问的数组
  2. NUM_TYPES 封装到一个变量中,这样我的文件中的不同位置就不会散布相同的文字

有什么建议吗?

[编辑] 在 C 常见问题解答中找到这个:http://c-faq.com/ansi/constasconst.html

【问题讨论】:

  • 如果你将它作为定义来代替会发生什么? #define kNUM_TYPES 4 ?
  • 这行得通...出于某种原因,我试图远离使用预处理器,因为我想我记得在某个地方读过它,但我只是做了更多的研究,找不到一个好的理由在这种情况下不要使用它。我认为如果我在预处理器中创建对象(如@"An NSString literal")可能不太理想。您的代码的唯一错误是不需要分号。
  • 啊,是的,感谢您的提醒,很高兴我能提供帮助。

标签: c objective-c arrays static constants


【解决方案1】:

这个警告的原因是const in c doesn't mean constant. It means "read only".所以值被存储在一个内存地址并且可能被机器码改变。

【讨论】:

  • 修改定义为const 的对象(例如通过从指针中丢弃const 并存储一个值)是未定义的行为;因此,此类对象的值是编译时或运行时常量(取决于存储持续时间)。该值不能简单地用于常量表达式,因为 C 标准没有说它可以。 (如果目标对象是在没有const 的情况下定义的或动态分配的,则允许丢弃const 并存储一个值;字符串文字不是const,但可能不会被写入。)
  • @jilles“可能被机器代码改变”并不意味着这个答案的作者的意思是“可能被C代码改变”。此外,这确实有另一个很好的理由:在不同的 TU 中可能存在 extern 常量,其值在编译当前 TU 时是未知的。
  • 改进此答案的一种方法是展示如何解决此问题。
【解决方案2】:

如果您仍然要使用预处理器,按照其他答案,那么您可以让编译器自动确定 NUM_TYPES 的值:

#define NUM_TYPES (sizeof types / sizeof types[0])
static int types[] = { 
  1,
  2, 
  3, 
  4 };

【讨论】:

  • 哇,这真的很酷...我不知道这是可能的。我认为这种计算的成本可以忽略不计。我是否还可以假设编译器可以将其优化为静态值?
  • 是的,sizeof 这样的对象的结果是一个编译时常量。
【解决方案3】:
#define NUM_TYPES 4

【讨论】:

    【解决方案4】:

    也可以使用枚举。

    typedef enum {
        typeNo1 = 1,
        typeNo2,
        typeNo3,
        typeNo4,
        NumOfTypes = typeNo4
    }  TypeOfSomething;
    

    【讨论】:

      【解决方案5】:

      正如其他答案中已经解释的那样,C 中的const 仅表示变量是只读的。它仍然是一个运行时值。但是,您可以在 C 中使用 enum 作为实常数:

      enum { NUM_TYPES = 4 };
      static int types[NUM_TYPES] = { 
        1, 2, 3, 4
      };
      

      【讨论】:

        【解决方案6】:

        恕我直言,这是许多 c 编译器的缺陷。我知道一个事实,即我使用的编译器不会在地址处存储“静态常量”变量,而是用非常常量替换代码中的使用。可以验证这一点,因为当您使用预处理器 #define 指令和使用静态 const 变量时,生成的代码将获得相同的校验和。

        无论哪种方式,您都应该尽可能使用静态 const 变量而不是 #defines,因为静态 const 是类型安全的。

        【讨论】:

        • 这听起来很糟糕,因为您可以获取static const 变量的地址。您所描述的行为可能是有效的优化,但它肯定不是总能奏效的。
        • 其实没问题。 C 编译器可以尽可能将 const 全局变量的个别使用替换为常量值。如果对变量的所有引用都转换为常量,则编译器可以将其完全删除。如果您在任何地方使用该地址,它将不会被删除。根据语言标准,这一切都没有改变,C 不允许以变量为大小的全局数组,无论变量是否为 const。
        猜你喜欢
        • 2012-11-18
        • 1970-01-01
        • 1970-01-01
        • 2014-03-07
        • 2019-11-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多