【C语言进阶深度学习记录】三十八 C/C++语言中的函数声明与函数定义
文章目录
- 1 函数的声明和定义
- 1.1 代码分析
- 2 总结
1 函数的声明和定义
- 声明的意义在于告诉编译器程序单元的存在。只是告诉编译器它存在但是不在声明这里定义,有可能在当前文件中的其他地方或者其他文件中定义。如果在它还没有被定义之前就使用它,会导致编译错误
- 定义则明确表示程序单元的意义
- C语言中,通过关键字extern进行程序单元的声明。现在的编译器可以省略不写,大多时候都是直接省略。
注意:在C语言中,当有多个源文件的时候,编译器共同编译这些源文件的顺序是不确定的。有可能先编译A文件,也有可能先编译B文件。这一点在下面的代码中会有体现。
1.1 代码分析
- 代码 lyy.c
#include <stdio.h>
#include <malloc.h>extern int g_var;extern struct Test;int main()
{extern void f(int i, int j);extern int g(int x);struct Test* p = NULL; // (struct Test*)malloc(sizeof(struct Test));printf("p = %p\n", p);//g_var = 10;printf("g_var = %d\n", g_var);f(1, 2);printf("g(3) = %d\n", g(3));free(p);return 0;
}
- global.c
#include <stdio.h>int g_var = 10;struct Test
{int x;int y;
};void f(int i, int j)
{printf("i + j = %d\n", i + j);
}int g(int x)
{return (int)(2 * x + g_var);
}
分析:
上述代码中,g_var和Test都是在global.c中定义的。在lyy.c中只是声明。上述代码编译运行会是正确的结果。
- 问题1:
但是,如果将g_var在global.c中的定义改为:float g_var = 10;的话,再编译运行上述代码的结果就是打印g_var的值是一个很大的随机值。这是为什么呢?
因为g_var 的定义是float类型,float类型在内存的存储方式与int类型在内存的存储方式是不一样。具体参见float的内存存储方式:【C语言进阶深度学习记录】三 浮点数(float) 在内存中的表示方法 .所以最终以int的方式打印g_var的时候,由于它本身在内存的存储方式导致打印出一个很大的数。
- 问题2:
如果将lyy.c中的这一行:struct Test* p = NULL;
改为:struct Test* p = (struct Test*)malloc(sizeof(struct Test));
那么再次编译程序就会报错:
这个错误是说Test是不完整类型。为什么会这样呢?在本文的刚开始已经说明:多个源文件一起编译,各个源文件的编译顺序是不确定的。在这里,很明显,在编译lyy.c的13行的时候,使用了sizeof求解Test结构体的大小,但是Test结构体此时由于编译器还没有编译到global.c,那么Test就是未定义的,根本无法使用sizeof求解它的大小所以编译器报错。
2 总结
- 声明和定义是不同的
【C语言进阶深度学习记录】三十八 C/C++语言中的函数声明与函数定义相关推荐
- 【C语言进阶深度学习记录】十八 条件编译的使用与分析
文章目录 1 基本概念 1.1 代码分析 1.2 通过命令行定义宏 2 #include 的本质 2.1 解决重复包含头文件的问题 3 条件编译的应用 4 总结 1 基本概念 条件编译的行为类似于C语 ...
- 【C语言进阶深度学习记录】十九 #pragma使用与分析
文章目录 1 #pragma 概念简介 1.1 #pragma message 的用法 1.2 #pragma once 的用法 1.3 #pragma pack 的用法 1.31 struct占用的 ...
- 【C语言进阶深度学习记录】十六 静态库与动态库的创建与使用
上一篇文章学习了编译的过程,点击链接查看:[C语言进阶深度学习记录]十五 编译过程简介,每一个C源文件编译后将会生成目标文件,那么这些目标文件,还需要链接起来,生成可执行文件. 文章目录 1 链接的意 ...
- 【C语言进阶深度学习记录】十五 编译过程简介
文章目录 1 初识编译器 2 总结 1 初识编译器 我们平时口中所说的编译器,是广泛的编译器.实际上,编译器包括了以下四个部分: 一个C代码被编译为可执行代码,包括以下几个过程: 下面就对上述的各个过 ...
- 【C语言进阶深度学习记录】十四 C语言中 三目运算符和逗号表达式
文章目录 1 三目运算符 1.1 三目运算符的返回类型的代码案例分析 2 逗号表达式 2.1 逗号表达式代码案例分析 2.2 如何用一行代码实现 strlen函数 3 总结 1 三目运算符 三目运算符 ...
- 【C语言进阶深度学习记录】十二 C语言中的:字符和字符串
文章目录 1 C语言中的单引号和双引号 1.1 双引号带来的BUG 2 总结 1 C语言中的单引号和双引号 C语言中的单引号用来表示字符字面量 C语言中的双引号用来表示字符串字面量,存储于全局的只读存 ...
- 【C语言进阶深度学习记录】十 C语言中:struct的柔性数组和union分析
本文并不讲C语言的基础 文章目录 1 空struct的大小 2 结构体与柔性数组 2.1 柔性数组的使用方法 2.2 柔性数组使用代码案例分析 3 C语言中的union分析 3.1 使用union判断 ...
- 【C语言进阶深度学习记录】二十六 C语言中的字符串与字符数组的详细分析
之前有一篇文章是学习了字符和字符串的,可以与之结合学习:[C语言进阶深度学习记录]十二 C语言中的:字符和字符串 文章目录 1 字符串的概念 1.1 字符串与字符数组 1.2 字符数组与字符串代码分析 ...
- 【C语言进阶深度学习记录】三十五 程序中的堆、栈以及静态存储区(数据区)
学习交流加 个人qq: 1126137994 个人微信: liu1126137994 学习交流资源分享qq群: 962535112 在我之前学习底层的知识的时候,也写过相关的内容.可以对比的学习:[软 ...
最新文章
- 新手必看,17个常见的Python运行时错误
- 微服务测试之静态代码扫描
- 【Elastic Stack学习】ELK日志分析平台(一)ELK简介、ElasticSearch集群
- VoWi-Fi能给LTE时代的语音通信体验带来什么?
- 【OFDM频域同步】基于OFDM数字电视地面广播系统中频域同步技术matlab仿真
- Java transient关键字使用小记
- 计算机在课堂中的应用论文,任务教学法在计算机教学中的应用论文
- oracle 10g体系结构及安全管理
- 深度学习中反向传播得到的损失是一个标量
- HDU - 4569 Special equations(同余模定理)
- 「offer来了」进程线程有啥关系?10个知识点带你巩固操作系统基础知识
- ASP.NET站点导航(五)
- 软件工程第二次作业中第一个作业
- Docker容器-cgroups资源配置
- linux 修改网卡 mac地址命令,Centos系统下查看和修改网卡Mac地址(附ifconfig命令格式)...
- 美计算机科学学者建议:加强青少年网络安全意识引导
- win10 ping网络计算机,win10 ping命令:如何ping网速和ping各个参数命令解释
- 新手教程篇-阿里云账号如何注册?
- Springboot中国古代史在线学习网站 毕业设计-附源码260839
- 2018年常见的13种APP推广方法 最后一种运营者必看