对 C 语言中变量的声明和定义,可以这样用类比 Java 的方式来理解吗? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
fantastM
V2EX    C

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

  •  
  •   fantastM 2021 年 3 月 3 日 2093 次点击
    这是一个创建于 1877 天前的主题,其中的信息可能已经有所发展或是发生改变。

    平时工作过程中主要写 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 语言中的变量声明。对变量声明、定义这两个概念可以这么理解么。
    9 条回复    2021-03-08 14:24:46 +08:00
    ipwx
        1
    ipwx  
       2021 年 3 月 3 日   1
    1. 完全错误
    2. 有点不太一样,建议不要用 java 去类比。
    3. 完全不对
    ----

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

    不过头文件还用来定义结构体和类
    yolee599
        3
    yolee599  
       2021 年 3 月 4 日 via Android
    C 语言是一个开放性很高的语言,什么写法都有,用 java 无法类比。指针和宏这两个东西很玄学
    BingoXuan
        4
    BingoXuan  
       2021 年 3 月 4 日   1
    请配合汇编一起学习,毕竟 C 是好看一点的汇编
    Shazoo
        5
    Shazoo  
       2021 年 3 月 4 日
    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
        6
    huang119412  
       2021 年 3 月 4 日
    K & R 也是 Java 之父高斯林的老师。所以 Java 的风格真的和 C 很像,大括号开头不换行,驼峰,String hash 等等都是来源 K & R 。而现 C 的风格是 ANSI C,和 K & R 并不一样。
    fantastM
        7
    fantastM  
    OP
       2021 年 3 月 4 日
    #2 @Kasumi20 原来如此……其实 C 的语法层面容易理解,不过我会多想为什么要这样设计,就容易想偏。

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

    感谢各位回复。
    Shazoo
        8
    Shazoo  
       2021 年 3 月 8 日
    @fantastM

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

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

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


    储备知识的话,还是多用多看吧。回想起来,C 也没有特别适合学习的开源代码。要不学习下嵌入式?这领域里面很多不错的 C Project 。
    fantastM
        9
    fantastM  
    OP
       2021 年 3 月 8 日
    #8 @Shazoo 感谢回复。我是准备学完 C 之后先看 Redis 的实现。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2803 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 69ms UTC 14:19 PVG 22:19 LAX 07:19 JFK 10:19
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86