精通C语言extern char k[] != extern char *k
Posted 从善若水
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了精通C语言extern char k[] != extern char *k相关的知识,希望对你有一定的参考价值。
本人就职于国际知名终端厂商,负责modem芯片研发。
在5G早期负责终端数据业务层、核心网相关的开发工作,目前牵头6G算力网络技术标准研究。
博客内容主要围绕:
5G协议讲解
算力网络讲解(云计算,边缘计算,端计算)
高级C语言讲解
Rust语言讲解
文章目录
extern char k[] 不等于 extern char *k
我们先看一个例子,大家就知道标题的含义了:
// file 1
unsigned long long CSRS[5]={0};
/* other code */
// file 2
extern unsigned long long *CSRS;
/* 其它引用变量CSRS的code */
上面的code对吗?
有些书籍会告诉你数组和指针大部分情况下是一样的,可以相互转换(interchangeable)使用,但是并没有告诉你什么情况下不可以随便转换使用。上面的例子其实是错误的,我们在这篇博文中向你介绍在上面code的情况下指针不等于数组。
下面看一个具体的例子:
// file 1
#include<stdio.h>
#include<stdlib.h>
extern void print_CSRS();
unsigned long long CSRS[5]={0};
int main()
{
/* 打印数组首元素的地址 */
printf("%s CSRS :%p\\n",__func__,CSRS);
/* 打印数组的地址 */
printf("%s &CSRS :%p\\n",__func__,&CSRS);
/* 使用calloc是为了分配的5个elements在逻辑地址上连续 */
unsigned long long *temp = (unsigned long long*)calloc(5,sizeof(unsigned long long));
for(int i=0;i<5;i++)
{
temp[i] = 123 + i;
CSRS[i]= (unsigned long long)(temp+i);
/* 按照指针格式打印 */
printf("%s CSRS[%d] :%p\\n",__func__, i, CSRS[i]);
/* 按照 unsigned long long 格式打印 */
printf("%s CSRS[%d] :%llu\\n",__func__, i, CSRS[i]);
}
printf("\\n");
print_CSRS();
return 0;
}
// file 2
#include<stdio.h>
//extern unsigned long long CSRS[];
extern unsigned long long* CSRS;
void
print_CSRS()
{
printf("%s CSRS :%p\\n",__func__,CSRS);
printf("%s &CSRS :%p\\n",__func__,&CSRS);
for(int i=0;i<5;i++)
{
printf("%s &CSRS[%d] :%p\\n",__func__, i, CSRS+i);
printf("%s CSRS[%d] :%llu\\n",__func__, i, CSRS[i]);
}
}
我们看运算结果:
我们这里先不解释为什么,下面会慢慢解释。我们再看一个正确的code,我们修改file 2:
// file 2
#include<stdio.h>
extern unsigned long long CSRS[];
//extern unsigned long long* CSRS;
void
print_CSRS()
{
printf("%s CSRS :%p\\n",__func__,CSRS);
printf("%s &CSRS :%p\\n",__func__,&CSRS);
for(int i=0;i<5;i++)
{
printf("%s &CSRS[%d] :%p\\n",__func__, i, CSRS+i);
printf("%s CSRS[%d] :%llu\\n",__func__, i, CSRS[i]);
}
}
正确的运行结果如下:
想要搞清除这个问题我们先要了解C语言变量的定义与声明的区别。
一、定义(Definition)与声明(Declaration)的区别
对象(object):C语言ISO标准中将对象一词解释为一个大小合适的内存块,这与C++的对象一词含义不同。
int a;//表示创建一个sizeof(int)大小的对象
定义(Definition) | 只能出现在项目中的一个位置 | 定义用来创建一个新的对象;确定对象的类型;预留内存 |
声明(Declaration) | 可以出现在项目中的多个地方 | 用来描述一个对象的类型;用来引用一个定义在其它位置的对象 |
定义是一种特殊的声明,它会为一个对象分配内存
二、编译器如何解释"extern unsigned long long CSRS[]"
每一个变量的地址在编译期就已经确定了。编译器对一个数组的引用可以用下图进行解释:
extern unsigned long long CSRS[]
- 编译器查询符号表找到变量 CSRS的地址 100(我们假设地址为100)
- 在程序运行期间获取变量i 的值,并于100相加
- 直接获取地址(100+i)处的值
三、编译器如何解释"extern unsigned long long *CSRS"
指针变量解引用(dereference)只能发生在运行期间。使用“extern unsigned long long *CSRS”其实就是告诉编译器CSRS是一个指针,这个指针指向的对象存储着一个类型为unsigned long long的值,要想获取这个值需要下面的步骤:
extern unsigned long long *CSRS
- 编译器查询符号表找到变量 CSRS的地址 100(我们假设地址为100)
- 获取地址100处的值5460(我们假设指针指向地址5460处)
- 再从地址5460处获取我们想要的值
四、重看上面的code
根据上面code的输出制作下图:
所以会产生下面的结果:
慢慢理解吧,毕竟C的精华就在指针上!!!
以上是关于精通C语言extern char k[] != extern char *k的主要内容,如果未能解决你的问题,请参考以下文章
undefined reference to `recvIpcMsg(int, ipc_msg*)'——#ifdef __cplusplus extern "C" { #e