你知道C语言中““的类型吗?

先看下面这个宏定义,这是我在阅读cjson源码的时候发现的,作用很简单,就是统计一个字串的长度。

/* strlen of character literals resolved at compile time */
#define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))

我通常的做法是直接使用下面的代码来统计。

strlen(string_literal);

两种方式对比的话,前者比后者效率高,在编译时就能计算出其结果,但后者更为通用,有些场景只能通过后者才能得出结果,所以追求效率就使用前者,追求通用就使用后者;但出于好奇,我写了如下的测试代码,奇怪的知识增长了不少。

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))

int main(int argc,char *argv[])
{
    char *p = "123";
    printf("%ld,%ld\r\n",static_strlen("123"),strlen("123"));
    printf("%ld,%ld\r\n",static_strlen(p),strlen(p));

    return 0;
}

结果:

3,3
7,3

从结果可以看到,直接传入字符串时,两者计算结果是一样的,然而使用指针的方式传入时,结果却不一样,前者得到的是指针的大小,而不是字串的长度,所以前者在使用上是有局限性的;间接的也说明了,字串"123"的类型并不是char *,因为C语言并没有原生的字符串类型,想到这儿也便明白了为什么在C++中char *p = "123";这句代码会报警告甚至是错误了。

那字串"123"的类型是什么呢,然后我用typeof看了一下(typeof是GNU的扩展,所以有些编译器可能不支持,其作用是获取一个变量或表达式的类型,更多细节自行查阅相关资料),从下图可以看到字串的类型为字符数组(以前我都称为常量字符串),准确的说是常量字符数组,因为其内容是只读的,为什么是只读的,后面会给出原因。

图片

上面的图中双引号中只有一个'\0',也就是只有一个元素的字符数组,既然是字符数组,那就可以用下标或者指针解引用的方式访问其内容了,于是就有了下面的操作。

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

int main(int argc,char *argv[])
{
    typeof("") test;
    test[0] = 5;
    printf("%d\r\n",test[0]);

    printf("%c,%c\r\n","123"[1],*("123" + 1));

    printf("%d,%d\r\n",""[0],*"");
    ""[0] = 5;//段错误,无法访问只读内容
    *"" = 5;//段错误,无法访问只读内容

    return 0;
}

结果:

5
2,2
0,0
段错误 (核心已转储)

从结果可以得知,虽然字串的类型为常量字符数组,但是通过typeof获取的类型定义的变量却不是只读的,而是可读可写的,凡事都有例外,当我使用g++编译整个程序时,却报错了,原因是通过typeof获取的类型定义的变量是只读的,看来C++对类型检查真是比C语言要严格很多很多;

后面的输出结果对于前面说的结论也有所印证。当然扩展的这些内容可能更偏向于娱乐了,在平时编程中可能没有人会这么干。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值