面试题答案
一键面试常量在内存中的存储方式
在Objective - C项目中,常量根据类型不同,存储方式有所差异:
- 基本数据类型常量(如int、float等):如果是全局常量(在函数外部定义),会存储在数据段(data segment)的只读数据区(rodata)。这个区域的数据在程序运行期间是只读的,多个实例共享同一份数据,节省内存空间。例如:
const int globalInt = 10;
这里的globalInt
就存储在只读数据区。如果是局部常量(在函数内部定义),如:
void someFunction() {
const int localInt = 20;
}
localInt
会存储在栈(stack)上,其生命周期与所在函数相同,函数结束后,栈上空间被释放。
2. 字符串常量:所有的字符串常量都存储在只读数据区。例如:
NSString *str = @"Hello, World!";
这里的@"Hello, World!"
存储在只读数据区,str
只是一个指向该字符串的指针。无论有多少个指针指向同一个字符串常量,内存中只有一份该字符串的副本。
3. 静态常量:用static
修饰的常量,如果是全局的,同样存储在数据段的只读数据区。例如:
static const int staticGlobalInt = 30;
静态全局常量在整个程序运行期间都存在,且存储在只读数据区,与普通全局常量类似,但它的作用域仅限于定义它的文件。
从内存优化角度合理定义常量
- 尽量使用全局常量:对于不会改变且在多个地方使用的值,定义为全局常量。因为全局常量存储在只读数据区,多个实例可以共享,避免了在不同地方重复定义导致的内存浪费。例如,定义一个项目中多处使用的数学常量
PI
:
const double PI = 3.141592653589793;
- 避免不必要的局部常量:如果一个值只在函数内部短暂使用,且其值并非真正意义上的常量(在函数执行过程中不需要保证其不变性),就不要定义为常量。因为局部常量存储在栈上,频繁创建和销毁会增加栈的开销。例如,如果在一个函数中临时计算一个值,这个值不需要在函数执行过程中保持不变,就不要定义为常量:
// 不好的示例
void badExample() {
const int tempValue = someCalculation();
// 后续代码使用tempValue
}
// 好的示例
void goodExample() {
int tempValue = someCalculation();
// 后续代码使用tempValue
}
- 使用
static const
定义文件内使用的常量:如果一个常量只在某个文件内使用,使用static const
修饰。这样不仅可以避免命名冲突,还因为其存储在只读数据区,从内存角度是优化的。例如,在某个.m
文件中定义一个只在该文件内使用的常量:
static const int filePrivateConstant = 42;
- 使用
#define
宏定义需谨慎:#define
宏定义是在预处理阶段进行文本替换,它没有类型检查,也不会像常量那样存储在特定的内存区域。虽然它在某些场景下很方便,如定义一些简单的代码片段,但从内存优化和类型安全角度,一般优先使用const
定义常量。例如,使用#define
定义一个常量:
#define MY_CONSTANT 10
这种方式会在预处理时将代码中所有MY_CONSTANT
替换为10
,如果在多个地方使用,可能会导致代码膨胀,而且没有类型信息。相比之下,使用const int myConstant = 10;
更为合理,它有明确的类型,且存储在合适的内存区域。