对 C 语言中变量的声明和定义,可以这样用类比 Java 的方式来理解吗?

2021-03-03 23:29:57 +08:00
 fantastM

平时工作过程中主要写 Java,因为对底层比较感兴趣,所以最近在学 C 语言和 Unix 。看 K & R 的过程中总体觉得都满顺畅的,不过因为自身对操作系统和编译原理不怎么了解,也没有 C 项目的实践经验……所以对书中提及的一些细节概念还不确定,想向各位请教一下。

  1. 把函数原型写到后缀名为 .h 的头文件,这种行为是不是类似于 Java 中的定义 interface,可以告诉调用方这些函数的调用方式,然后头文件中声明的函数原型类似于 Java 中的 interface 的方法。
  2. 在 C 语言中,对于外部变量的 static 关键字,可以类比为 Java 中的 private 关键字吧,用于将变量的作用域限制在当前的源文件(在 Java 中是对象)中,避免对全局环境造成影响。
  3. K & R 书中提及「将外部变量的 声明定义 严格区分开来很重要」,还有一个初始化的概念。变量的声明仅是说明变量的类型,不会引起存储器的分配,例如使用 extern 关键字仅是表示它声明的变量是来自于外部源文件中。变量的定义是在变量声明的基础上,还会引起存储器的分配存储单元。然后,变量的初始化和赋值是需要在存储器分配存储单元(也意味着是需要在变量定义)之后才能进行的吧,如果仅是变量声明的话,则无法进行变量的初始化和赋值。在 Java 中 new 对象时候,类的成员字段在没有显式初始化的情况下,会被赋予一个默认值,这样的行为是不是可以理解为 C 语言中变量定义 + 初始化的这两个概念?另外,Java 类的方法中的变量不会被初始化,(下面是一些假设)如果 JVM 是在 int a; 这一步中为变量分配存储单元的话,那么这就应该理解为 C 语言中的变量定义,如果 JVM 是在 a=10; 这一步中为变量分配存储单元的话,而不是 int a; 的话,那么 int a; 就应该理解为 C 语言中的变量声明。对变量声明、定义这两个概念可以这么理解么。
1492 次点击
所在节点    C
9 条回复
ipwx
2021-03-03 23:45:34 +08:00
1. 完全错误
2. 有点不太一样,建议不要用 java 去类比。
3. 完全不对
----

学新语言大忌:类比。建议好好学习 C 语言。关注重点:C 语言编译过程、.c => .o 是怎么回事,link 这个步骤是什么。然后看看编译出来的 .o 文件和可执行文件的符号表
Kasumi20
2021-03-04 01:15:02 +08:00
写函数原型其实只是因为编译器垃圾,没办法向后查找

不过头文件还用来定义结构体和类
yolee599
2021-03-04 08:31:41 +08:00
C 语言是一个开放性很高的语言,什么写法都有,用 java 无法类比。指针和宏这两个东西很玄学
BingoXuan
2021-03-04 09:43:24 +08:00
请配合汇编一起学习,毕竟 C 是好看一点的汇编
Shazoo
2021-03-04 09:51:20 +08:00
C 语言的写法其实是直接面向编译器和链接器的。

像是.h 文件也好,.x 文件也好,include 后,都是等同于预编译阶段将目标文件内容递归拷贝到当前位置。(是的,你可以直接 include .c 文件,很多嵌入式领域直接利用宏来 include 不同 c 文件,用来配置 rom 某处的 payload 。没错,你都可以指定某个巨型数组 link 到绝对地址内。

所以,C 不存在什么 interface 之类的玄学概念。每次编译,其实就是编译一个完完整整的庞大无比的标准 C 文件。( so,你改动一个很多文件都 include 的头文件,会造成所有 C 文件重编译)

同理,static 在编译器内的规则很简单,限制不能被其他文件调用即可;在 linker 里面,实际上是根据不同 linker 自己去定义。大致理解为 link 到全局堆内分配。

C 很有趣,各种魔幻写法,lz 类比 java 有点不合理,java 在 C 程序员眼里才是玄学,各种限制。学 C,类比汇编可能好些。

可以复习下编译原理和体系结构再学 C 。
huang119412
2021-03-04 10:48:27 +08:00
K & R 也是 Java 之父高斯林的老师。所以 Java 的风格真的和 C 很像,大括号开头不换行,驼峰,String hash 等等都是来源 K & R 。而现 C 的风格是 ANSI C,和 K & R 并不一样。
fantastM
2021-03-04 11:26:56 +08:00
#2 @Kasumi20 原来如此……其实 C 的语法层面容易理解,不过我会多想为什么要这样设计,就容易想偏。

#5 @Shazoo 感谢指点!学习操作系统 /编译原理之类的底层知识正是我这次学习 C 语言的目的,另外想再请教一下理解「将外部变量的 **声明** 与 **定义** 严格区分开来很重要。变量声明用于说明变量的属性(主要是变量的类型),而变量定义除此以外还将引起存储器的分配」这句话,需要哪些储备知识呢?

感谢各位回复。
Shazoo
2021-03-08 09:07:51 +08:00
@fantastM

「将外部变量的 **声明** 与 **定义** 严格区分开来很重要。变量声明用于说明变量的属性(主要是变量的类型),而变量定义除此以外还将引起存储器的分配」

这句话是新手向的教条。实际上,你只需要知道以下:
某个 var 被定义也好,extern 引用也好,在编译阶段都是无差别的。只是告知编译器,有这么个变量,你知道这货是啥玩意后,tm 别报错。
在链接阶段,extern 无用,应该有且仅有一个定义。这是因为,链接就需要确定这个变量真实地址位置了。多个的话,自然是不现实的。

工程上多人配合,一般应用范围广的全局变量都是有个专门的 extern 用的 h,和定义用的 C 。适合 5w 量级的项目。你可以试试,傻瓜化,也好用,不过量级上去了,改动就重编译,也很烦。


储备知识的话,还是多用多看吧。回想起来,C 也没有特别适合学习的开源代码。要不学习下嵌入式?这领域里面很多不错的 C Project 。
fantastM
2021-03-08 14:24:46 +08:00
#8 @Shazoo 感谢回复。我是准备学完 C 之后先看 Redis 的实现。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/758211

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX