在文件范围内可变地修改数组


85

我想创建一个恒定的静态数组,以便在我的Objective-C实现文件中使用,类似于在“ .m”文件的顶层进行如下操作:

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


2
如果您改为将其作为定义怎么办?#define kNUM_TYPES 4
豪尔赫·以色列·佩尼亚

那行得通...出于某种原因,我试图不使用预处理器,因为我以为我记得在某个地方读过它,但是我做了更多的研究,没有找到在这种情况下不使用它的充分理由。我认为,如果我要在预处理器中创建对象(例如@"An NSString literal"),可能就不太理想了。您的代码段唯一的问题是不需要分号。
山姆

啊,是的,感谢您的注意,很高兴我能提供帮助。
豪尔赫·以色列·佩尼亚

Answers:


62

该警告的原因是c中的const并不意味着常量。它的意思是“只读”。 因此,该值存储在内存地址中,并且可能会被机器代码更改。


3
修改定义的对象const(例如,通过抛弃const指针并存储值)是未定义的行为。因此,此类对象的值是编译时或运行时常量(取决于存储持续时间)。该值不能仅在C标准中不能使用就可以在常量表达式中使用。(const如果未定义目标对象const或未动态分配目标对象,则const可以放弃
并存储值

3
@jilles“可能会被机器代码更改”并不意味着该答案的作者意味着“可能会被C代码更改”。此外,这确实有另一个很好的理由:extern在不同的TU中可能存在常量,在编译当前TU时其值未知。

14
改善此答案的一种方法是显示如何解决此问题。
乔治·斯托克

32

如果仍然要使用预处理器(按照其他答案),则可以使编译器NUM_TYPES自动确定值:

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

哇,真是太酷了……我不知道那是可能的。我认为这种计算的成本可以忽略不计。我是否还可能认为编译器可以将其优化为静态值?
山姆

2
是的,sizeofon这样的对象的结果是一个编译时常量。
caf



4

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

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

3

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

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


这听起来很糟糕,因为您可以使用static const变量的地址。您所描述的行为可能是有效的优化,但肯定不是总能奏效的。
2016年

真的很好。对于C编译器,可以在可能的情况下用常量值替换const全局变量的单个用法。如果所有对变量的引用都转换为常量,则编译器可以将其完全删除。如果您在任何地方使用该地址,它将不会被删除。根据语言标准,这些都没有改变,C不允许全局数组使用变量作为大小,无论变量是否为const。
埃文(Evan)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.