字符数组作为编译时常量:C标准合规性与可移植性问询
C标准中静态对象初始化的相关条款依据
核心区别解析
用const char *str = "Hi!"初始化的指针是变量——即便它指向只读字符串,其自身存储的地址值虽固定,但不属于编译时常量,因此无法用于静态结构体的初始化;而静态数组static const char str[4] = {'H','i','!','\0'}的数组名str,在初始化语境中会被隐式转换为指向首元素的地址常量,属于合法的编译时常量,可用于静态对象初始化。
可验证代码示例
以下代码可在GCC、Clang编译器下通过-Wall、-Wextra、-Wpedantic、-Weverything(仅Clang)及-std=c89编译:
#include <stdio.h> /* 错误写法:指针变量无法作为静态初始化器 * static const char *str = "Hi!"; */ static const char str[4] = {'H', 'i', '!', '\0'}; static struct { double x; const char *string; } my_struct = {1.0, str}; int main(void) { puts(my_struct.string); return 0; }
C89标准条款参考
1. 常量表达式的定义(§6.1.3.3)
常量表达式是程序翻译阶段即可计算出值的表达式,不得包含任何对象的值,除非该对象是用常量表达式初始化的静态存储期对象。
静态数组str属于静态存储期对象,且初始化器是字符常量组成的列表(属于常量表达式),因此其数组名转换后的指针值是编译时可确定的地址常量,符合常量表达式要求,可用于静态对象初始化。
2. 静态对象的初始化要求(§6.5.7)
静态存储期的对象必须用常量表达式初始化。
对于static const char *str = "Hi!",str是指针变量,其值(字符串地址)虽然固定,但str本身是变量,引用它的值不属于常量表达式,因此用它初始化静态结构体成员违反该条款,属于非法写法。
3. 数组名的隐式转换(§6.2.2.1)
数组类型的表达式在多数语境下会被转换为指向该数组首元素的指针类型表达式,转换结果为地址常量。
这正是数组名str能作为静态初始化器的关键:它被自动转换为编译时确定的首元素地址,满足静态初始化对常量表达式的要求。
内容的提问来源于stack exchange,提问作者Ryan Maguire
相关产品推荐
相关产品推荐

