文章目录

  • 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++语言中的函数声明与函数定义相关推荐

  1. 【C语言进阶深度学习记录】十八 条件编译的使用与分析

    文章目录 1 基本概念 1.1 代码分析 1.2 通过命令行定义宏 2 #include 的本质 2.1 解决重复包含头文件的问题 3 条件编译的应用 4 总结 1 基本概念 条件编译的行为类似于C语 ...

  2. 【C语言进阶深度学习记录】十九 #pragma使用与分析

    文章目录 1 #pragma 概念简介 1.1 #pragma message 的用法 1.2 #pragma once 的用法 1.3 #pragma pack 的用法 1.31 struct占用的 ...

  3. 【C语言进阶深度学习记录】十六 静态库与动态库的创建与使用

    上一篇文章学习了编译的过程,点击链接查看:[C语言进阶深度学习记录]十五 编译过程简介,每一个C源文件编译后将会生成目标文件,那么这些目标文件,还需要链接起来,生成可执行文件. 文章目录 1 链接的意 ...

  4. 【C语言进阶深度学习记录】十五 编译过程简介

    文章目录 1 初识编译器 2 总结 1 初识编译器 我们平时口中所说的编译器,是广泛的编译器.实际上,编译器包括了以下四个部分: 一个C代码被编译为可执行代码,包括以下几个过程: 下面就对上述的各个过 ...

  5. 【C语言进阶深度学习记录】十四 C语言中 三目运算符和逗号表达式

    文章目录 1 三目运算符 1.1 三目运算符的返回类型的代码案例分析 2 逗号表达式 2.1 逗号表达式代码案例分析 2.2 如何用一行代码实现 strlen函数 3 总结 1 三目运算符 三目运算符 ...

  6. 【C语言进阶深度学习记录】十二 C语言中的:字符和字符串

    文章目录 1 C语言中的单引号和双引号 1.1 双引号带来的BUG 2 总结 1 C语言中的单引号和双引号 C语言中的单引号用来表示字符字面量 C语言中的双引号用来表示字符串字面量,存储于全局的只读存 ...

  7. 【C语言进阶深度学习记录】十 C语言中:struct的柔性数组和union分析

    本文并不讲C语言的基础 文章目录 1 空struct的大小 2 结构体与柔性数组 2.1 柔性数组的使用方法 2.2 柔性数组使用代码案例分析 3 C语言中的union分析 3.1 使用union判断 ...

  8. 【C语言进阶深度学习记录】二十六 C语言中的字符串与字符数组的详细分析

    之前有一篇文章是学习了字符和字符串的,可以与之结合学习:[C语言进阶深度学习记录]十二 C语言中的:字符和字符串 文章目录 1 字符串的概念 1.1 字符串与字符数组 1.2 字符数组与字符串代码分析 ...

  9. 【C语言进阶深度学习记录】三十五 程序中的堆、栈以及静态存储区(数据区)

    学习交流加 个人qq: 1126137994 个人微信: liu1126137994 学习交流资源分享qq群: 962535112 在我之前学习底层的知识的时候,也写过相关的内容.可以对比的学习:[软 ...

最新文章

  1. 新手必看,17个常见的Python运行时错误
  2. 微服务测试之静态代码扫描
  3. 【Elastic Stack学习】ELK日志分析平台(一)ELK简介、ElasticSearch集群
  4. VoWi-Fi能给LTE时代的语音通信体验带来什么?
  5. 【OFDM频域同步】基于OFDM数字电视地面广播系统中频域同步技术matlab仿真
  6. Java transient关键字使用小记
  7. 计算机在课堂中的应用论文,任务教学法在计算机教学中的应用论文
  8. oracle 10g体系结构及安全管理
  9. 深度学习中反向传播得到的损失是一个标量
  10. HDU - 4569 Special equations(同余模定理)
  11. 「offer来了」进程线程有啥关系?10个知识点带你巩固操作系统基础知识
  12. ASP.NET站点导航(五)
  13. 软件工程第二次作业中第一个作业
  14. Docker容器-cgroups资源配置
  15. linux 修改网卡 mac地址命令,Centos系统下查看和修改网卡Mac地址(附ifconfig命令格式)...
  16. 美计算机科学学者建议:加强青少年网络安全意识引导
  17. win10 ping网络计算机,win10 ping命令:如何ping网速和ping各个参数命令解释
  18. 新手教程篇-阿里云账号如何注册?
  19. Springboot中国古代史在线学习网站 毕业设计-附源码260839
  20. 2018年常见的13种APP推广方法 最后一种运营者必看

热门文章

  1. spring mvc学习(54):简单异常处理
  2. java学习(100):集合类简介
  3. Python多个版本指定如何指定
  4. 三相阻容降压供电DCDC电源
  5. Linux SPI总线和设备驱动架构
  6. Linux命令 - watch
  7. CSS之Box-sizing
  8. PyTorch 系列 | 数据加载和预处理教程
  9. Web前端3.0时代,“程序猿”如何“渡劫升仙”
  10. appium学习记录1