1 什么是字符串字面量
在C语言中,形如"hello world"
的字符串即为字符串字面量(常量)。与之对比的是字符串变量,也即字符数组,形如char arr[] = "hello world"
。两者在用法上有很多相似之处,但两者的存储属性是截然不同的。
2 编译器眼中的字符串字面量
我们经常会看到这种字符串字面量的用法:
const char *p = "hello world";
但千万不要以为在编译器眼里字符串字面量是const char *
,之所以要强调这一点,是因为这会影响我们对sizeof("hello world")
行为的判断。
就单字节字符而言,其类型是char[N]
,N为字符串的长度。因此sizeof("hello world")
的结果为12。上述用法也显得很自然,毕竟在C语言中,将数组(首地址)赋值给数组元素的指针变量是合法的:
char a[] = "test";
char *p1 = a, *p2 = NULL;
p2 = a;
3 存放在哪里
字符串字面量和字符数组有一个很重要的差别:前者是只读的,若程序试图修改字符串字面量,那么结果是未定义的;后者是可读可写的(除非主动使用const修饰)。
产生这种差别的根本原因,个人认为源于两者语义的不同。字面量本身就是常量,常量自然是不能修改的。这种不能修改的属性是如何做到的呢?这就要说到字符串字面量的存储属性了。编译器通常会将,字符串字面量放在.rodata
,而这个section在被加载到内存时,其所在页面会被标记为只读,因此就从硬件上实现了只读。但这也不绝对,编译器并不总是会这么做,C标准并未明确定义写字符串字面量时的行为。
此外,在嵌入式环境下,通常我们需要自己写链接脚本,这时就需要注意编译器将字符串字面量放在哪个section,我们应当在链接脚本中将这个section安排到只读的存储介质中。不仅如此,对于某些地址总线和数据总线分开且寻址范围也分开的哈佛架构,我们还应当将字符串字面量安排到数据总线能够寻址的区域。
4 常用法
4.1 传参
printf("hello world\n");
4.2 赋值
const char *p = "hello world\n";
4.3 接续
/* 使用\n */
printf( "first
second
third" );
/* 使用\ */
printf( "first \
second \
third" );
/* 使用"" */
printf( "first "
"second "
"third" );
4.4 下标访问
char c = "abc"[0]; /* c is 'a' */
参考
[1] String literals
[2] string-literals-where-do-they-go
[3] Introduction to C / C++ Programming-Character Strings