百科问答小站 logo
百科问答小站 font logo



编程语言为什么有变量类型这个概念? 第1页

  

user avatar   s.invalid 网友的相关建议: 
      

因为……我们有一个梦想:如果我们随便提一下计算机就知道该怎么做、如果有什么程序可以自动识别程序里的逻辑错误,那该有多好啊!!!


实践中,无论你学习数学、物理还是别的什么,数字都是有类型的。

比如说,桌子两条边的夹角是90度,这个90就是有类型的,为了方便,我们记为90°。

然后,同样的,桌子的宽度是90厘米,这个90就是一个长度类型的数据,记为90cm。


这两个90是不能直接加的。桌子边长90cm,加上桌角90°,得个180——什么鬼东西这是?


类似的,有人调侃小学数学题:红色的恒星表面温度是4000℃,蓝色的恒星表面温度是9000℃,问它们的温度加起来等于多少?

问这种题目的都是弱智,对吧。“不同恒星表面温度加起来”是没有意义的。


进一步的,物理学有个手段叫“量纲分析”,简单说就是让数据的单位也参与运算,比如加速度的单位就是(米/秒²)。

那么,当你总结出一个物理公式时,就可以先做个“量纲分析”:公式等号左右两边算出来的东西,其量纲一样吗?不一样就丢掉吧,肯定错了!

类似的,两个项做加减?它们的量纲一样吗?不一样?你把加速度和速度加起来算什么鬼。


能通过量纲分析的也未必就对,但通不过量纲分析的肯定是个错误。

借助这个工具,我们可以花费尽量小的代价、尽量快的识别出错误,避免浪费更多时间。


类似的,在程序中,我们也可以借助类型,让编译器帮我们查错。


比如,小张的生日是7月1日,小王月薪¥12000;程序员脑抽,写了个计算公式:

       int sum = zhang.birthday+wang.salary;     

编译器马上就可以指出这是个错误:

错误,+两侧数据类型不匹配:datetime型数据和decimal型数据之间不能执行+操作。



不仅如此,我们还可以借助类型,让编译器“心领神会”的帮我们选择(dispatch)正确操作。

比如,我们要给小张记个功,给小王涨100块钱薪水;如果没有类型系统,那么你可能得这样写:

       //zhang.CV指向一块字符串区域,要往末尾续写就要计算原有CV的长度 zhang.CV = strcpy(zhang.CV + strlen(zhang.CV), "10月1日获得个人三等功。");  wang.salary += 100;     

很麻烦,对吧。

但如果zhang.CV是一个string类型,那么就简单了:

       zhang.CV += "10月1日获得个人三等功。";  wang.salary += 100;     

编译器知道“字符串的+操作就是往后面拼凑另一个字符串”,和decimal的数值增加不是一回事;而我们就可以忘记底层差异,都写成+=就行了,编译器会自动选择正确实现。


程序写起来是不是就变得简洁快捷多了?程序员的记忆负担是不是也减轻了?



假设你参加单位组织的知识竞赛,理论上你可以知无不言言无不尽,可以在试卷上奋笔疾书、充分展示自己的才华……

但现实中呢,答题有时间限制,不可能让你一个人说一天;试卷留的空白有限,不允许你长篇大论——有些不太专业的人甚至会搞出“试卷上留白太少写不完答案”之类飞机。于是你只能留下一句名言“我知道答案,但是地方太小写不下”……


计算机也一样:我们的内存并不是无限的,不可能允许你在“性别”里面填写“12岁前男12岁后女18岁后女变男20岁后男变女”……

咳咳,开个玩笑。实践中,很多时候,一个字节也是生死攸关的。比如你要处理几千万条信息,如果每条信息压缩一个字节,它可能就能放到内存里完成;但多了一个字节……


Out Of Memory,BOOM!


在正常使用的数据结构里,人的年龄一般是个unsigned char,单字节无符号整数最大可以表示到255,足够用了;如果你搞错了:

       wang.age = wang.salary     

编译器就会告诉你,“薪水”使用的类型decimal太大,放不到年龄使用的无符号单字节整型里面(提示你“操作可能造成数据溢出”)。


不仅如此。

如果完全用二进制表示整数或者简单定点数,那么天文数字(比如十后面三四十个零)、高精度小数(精确到小数点100位,但前90位都是0),这些是不是也太浪费空间了?当然应该上基于科学计数法的单精度、双精度数啊。

再比如,二进制仅仅是数字,英文字符、中文方块字,这些怎么表示?

因此,我们不得不制定各种各样的编码方案;而不同的编码方案支持的运算法则、具体的运算过程,肯定是不一样的。


比如,对应到CPU整数指令上,就有“单字节加”“双字节加”“四字节加”“八字节加”乃至“有符号数加”和“无符号数加”和“加进位位的加”和“不加进位位的加”等等区别;甚至BCD码表示的整数在加法运算后还必须附加一个DAA指令完成调整(相应的,减法要用DAS指令调整)……

这些,都是半点混淆不得的。

这还仅仅是整数加减法运算。再加上单精度、双精度浮点数,再加上四则运算以及正切余切平方求根取对数等等等等……

明白为什么现在没人用汇编编程了吧?


这些东西,都可以借助类型系统,让编译器自动的安排合适指令、确保计算结果正确。

说白了,这还是前面提到的dispatch(当然,同时还有类型匹配与否的检查)。


过去,编程语言的类型系统往往仅仅包含“基本类型”的完整支持,对用户自定义数据结构只有有限的支持;面向对象彻底的改变了这一点:从此,就连用户自定义数据结构,也可以通过“晚绑定”在运行时dispatch了。


与之同时,面向对象编程也增加了“接口检查”之类动作——你可以调用 Person.Run(),但调用Stone.Run()编译器就会报错。因为“石头不会跑”。


这东西继续发展,还有强类型、弱类型,动态类型、静态类型,以及“我不关心你的类型,只关心你能不能执行某个操作”的鸭类型等等东西。


但归根结底,类型系统做的就是两件事:

1、根据类型安排合适的操作

2、借助类型系统发现部分逻辑错误


做为初学者、业余开发者,类型系统对你可能是个束缚,因为你实在搞不明白这东西是干嘛用的、为什么有那么多类型、这些类型都有哪些差异。那么“无”类型的脚本语言对你来说就非常方便。


但实际上,哪怕号称“只有字符串一种类型”的TCL语言也是支持各种数据类型的。只是在你看不见的地方,这种语言自动替你做了类型转换而已。

这种隐式转换反而容易形成很多“坑”。比如知乎上经常被吐槽的JavaScript,甚至因为数据值的不同,其加法、判断等等等操作都会有不同结果——想要用好它,你就不得不死记硬背这些结果,或者写个表达式就上网查查真伪……呸,是上网查查“加法的正确用法”。这显然太过累人了。


对专业开发者,如前所述,类型系统是个极为重要极为犀利的工具。

用好它,一方面可以借助它的“自动分派”简化程序,另一方面又可以借助“类型检查”自动探测出很多很多的错误。

你的程序越复杂、规模越大,类型系统的重要性就越突出。


user avatar   lu-luce 网友的相关建议: 
      

扯什么计算机体系结构的其他回答都是学生吧。。

原因很简单。

因为,编程语言的类型存在的目的是防止出错。但是不防止欺骗。

举个例子,我经常遇到这种情况。一个对象叫PhonePrice保存了一款手机的价格,另一个对象叫CustomerAge保存了一个顾客的年龄。两个其实保存的都是一个整数。但是能不能互相赋值。从业务上就是不行。

你写 PhonePrice a; CustomerAge b; a = b ; 编译器就是需要报错。

但是你要是非写成a.value = b.value ; 编译器也一点办法都没有。

还比方,当程序员把一个字符串赋值给一个整数的时候,编译器可以告诉程序员。

你会不会有可能写错了。

而不会理解成把字符串的首地址取出来,转换成整数,赋值给一个整数。

反过来说,我作为程序员,我就把字符串的首地址取出来,转换成整数,赋值给一个整数。编译器也一点办法都没有。

这就和汽车上油量低报警一样。你说没有这个功能,没有油以后,车辆直接停在高架行不行。作为一个汽车,我就负责发动机从油箱吸油转动轮子。然后汽车要求驾驶员每隔一个小时检查一下油量行不行。

从完成功能的角度来说,是可以的。但是这个是不是很操蛋。

编程语言的工作场景不是学校教授用粉笔证明定理。而是工业化场景。在工业上使用的时候,就是要有防呆和报警保护。


user avatar   d41d8c 网友的相关建议: 
      

C语言的前身B语言就没有类型。

One major difference between B and Fortran is that B is a typeless language: there is no analog in B of the Fortran IJKLMN convention. Thus a, b, c, and sum are all 36-bit quantities, and arithmetic operations are integer.

(来源:bell-labs.com/usr/dmr/w [1]

但是B语言用起来有些难受。比如因为没有字符类型也没有字符串指针(指针解引用的结果都是36位的值),要读取字符串中的字符,需要调用char(s, n)函数;要改变字符串中的字符,需要调用lchar(s, n, c)函数。

B语言的问题在按字节寻址的新机器(指PDP-11)上表现得更为明显。这种难受是Dennis M. Ritchie发明C语言的第一个原因。

First, its character-handling mechanisms, inherited with few changes from BCPL, were clumsy: using library procedures to spread packed strings into individual cells and then repack, or to access and replace individual characters, began to feel awkward, even silly, on a byte-oriented machine.

(来源:bell-labs.com/usr/dmr/w

所以如果不区分变量类型,还是能做出实用的编程语言的,但是,用着不爽啊。

(另外LISP、Python和JavaScript等动态类型编程语言有“变量没有类型,值有类型”的说法,大概是承认了“变量类型”不是必要的,但“类型”还是需要的。)

参考

  1. ^ 顺带一提,这篇是hello, world的最早出处

user avatar   ling-jian-94 网友的相关建议: 
      

简单解释的话,数据存在内存里都是一样的字节序列,但是解释为整数、浮点数、字符串的时候会产生不同结果,如果编程语言不记住每个位置上是按什么格式存取数据的,就必须要程序员每次存取的时候自己记清楚,这样很不方便,出了错误很难排查。类型的意义就是限定了每个存储位置上存储的数据,除了特殊情况之外,都以相同的解释方式(整数、浮点数、字符串)使用,这样就不容易把代码写错。

类型系统不是必须的,比如汇编语言就没有类型系统,同一个地址既可以读进通用寄存器也可以读进浮点寄存器,需要程序员自己记清楚,不会去检查。C这样的语言选择在编程时指定每个变量的类型,编译时进行检查,这种做法称为静态类型系统,编译完成之后类型信息是可以去掉的。Python这样的语言通过数据结构将类型和数据放在一起存储,在运行中可以检查每一段数据的具体类型,这种系统称为动态类型系统。


user avatar   Ivony 网友的相关建议: 
      

这个问题你要拔高有很多东西可以讲,但是我觉得那完全偏题了。

因为题目问的是,为什么最初要给变量设计类型这个概念。


那很简单,因为CPU就有类型……

当然说CPU有类型是不够准确的,因为CPU并没有类型的概念,他是用不同的指令来解决这个问题的:

譬如说两个整形相加就是ADD指令,两个浮点型相加是FADD指令(当然这里都是汇编简码,CPU用的是机器码)。

需要区分这两者的原因也非常简单,因为这两者执行的操作是完全不同的。


很显然,人们写代码的时候,不喜欢自己去区分整形相加和浮点型相加,所以就发明了高级语言例如C,C使得我们可以用单一符号也就是"+"描述整形或者浮点型的相加。

但是为了搞清楚每一个+到底对应到ADD还是FADD,C语言就设计了类型。


就这么简单,所以类型最开始就是为了让表达式呈现不同行为。什么意思呢?就是说同一个表达式a+b,在不同的上下文(类型就是上下文)呈现出不同的实际操作(CPU的指令)来满足同样的期望(求和)。

当然,类型也可以避免程序员的一些低级错误,例如对浮点数进行ADD操作,最终得到与预期不符的结果……


当然,更根本的来讲,类型的概念是内生存在的,类型决定了数据如何解读和运算。譬如说CPU指令要区分ADD和FADD,你当然可以说是因为ADD和FADD的实际行为不同,但是为什么ADD和FADD的实际行为不同呢?本质上就是浮点数的解读和运算方式与整型数据的解读和运算方式不同。也就是说类型不是被设计出来的,他本身就是数据解读(存储读取传输)和运算方式的pattern(比如说我们通常说的浮点数就是遵循IEEE754标准的实现)。



==========================================================


补充看到的评论:

很专业。顺便问个问题,我是教C语言的老师,上次讲到变量,我和学生说道,变量有三个基本属性,类型,变量名和值,这三个属性是理所当然存在的。有学生在抬杠问我,为啥类型的存在是理所当然的。我只好用类型决定了内存数据编码方式这个角度回答,但我知道我的回答算是个回答,但也是回避了问题。如果是你,这个问题你如何回答?我所面对的是C语言初学者。给个建议吧。

不好意思,就我看来,你这个学生提出的问题比你这个问题要深刻得多得多的多的多,那才是一个极好的问题

我们换个说法如何?

变量的类型是不是必须的?


还真不是,所以这是一个极好的问题。

变量的类型的确就不是必须的。


要我回答,我会回答他你提出了一个极好的问题,类型的确不是必须的,但是没有类型的话,会很麻烦。如果你非要说必要性,那变量本身也不是必须的。所以,变量不一定要类型,但是我们写程序也不一定非要变量啊。


user avatar   pansz 网友的相关建议: 
      

不需要,我已经几乎两年没用过有线充电了。

把常用场合都部署好无线充电以后,真的不用操心换手机换充电器之类的事情。

其实很简单的一个问题:取消耳机口之后,各位是改用L口耳机C口耳机,还是改用无线耳机?我曾经以为会普及L口或者C口耳机,然而现实就是无线耳机开始普及。

无线充电座普及之后,由于它没有插拔,所以她的寿命其实远比手机要长。

--

所以,如果你没有无线充,强烈建议你尝试无线充。


user avatar   DBinary 网友的相关建议: 
      

monster girl island




  

相关话题

  一行 Java 代码(以分号结束)能实现什么丧心病狂的功能? 
  初中文凭可以学习编程吗?如果可以,是去靠谱的培训机构还是自学?学习方向都有哪些?就业环境如何? 
  有哪些编程上的中文术语让人困惑,但是看英文就一目了然的? 
  如何理解「由于脚本在服务器上执行,因此浏览器在不支持脚本的情况下就可以显示服务器端的文件」? 
  现在计算机大厂985本科是不是难进了? 
  为什么程序员有那么多过劳死的,知乎上还是乐此不疲的劝人转计算机专业? 
  为什么很多人反对中文在编程中的使用? 
  一行 Java 代码(以分号结束)能实现什么丧心病狂的功能? 
  怎么培养数据分析的能力? 
  为什么有些验证码看起来很容易但是没人做自动识别的? 

前一个讨论
typename = int 这种语法的意义是什么?
下一个讨论
知乎上有传闻说:资深英语翻译(十年工作经验)在中国一线城市的年薪能够达到二十万人民币以上,这是真的吗?





© 2024-12-25 - tinynew.org. All Rights Reserved.
© 2024-12-25 - tinynew.org. 保留所有权利