我正在学习 C 和汇编语言。我注意到,与 C 相比,汇编是一种无类型语言,它需要在处理数据之前声明数据类型。但我也了解到,即使用 C 编写的代码也会首先编译成用汇编编写的代码,然后汇编成目标代码。这意味着我们在 C 中使用的数据类型声明或任何高级语言仅用于 C 编译器。它们对目标代码没有任何特殊影响。这是对的吗?
我收集的是类型声明告诉编译器可以对数据执行的操作,数据大小(在数据段中存储数据所需),可存储的最大和最小十进制数的大小。我这样说是对的吗?
类型声明还有其他好处吗?
答案 0 :(得分:9)
在C中,我们有一个简单的类型系统,但它不是特别复杂,可以(并且经常在实践中)被完全未经检查的强制转换等规避。(由于这些原因,C通常被称为“弱类型”,这是不明确的,通常用于抨击语言,但至少告诉类型不 重要。)类型的大小,布局和对齐不固定,虽然它通常会与同一平台上的相同编译器(版本)保持一致。 int
可能是14位大等等,这些都不能保证(除了C标准要求基本积分类型之间有一些排序,例如short
不能大于{{ 1}})。
程序员不知道细节,但编译器确实需要。例如,为int
生成的确切代码foo.y
和struct Foo { int x; short y; };
取决于例如struct Foo foo;
关于int
和short
以及struct Foo
的填充的确切大小,当它编译为“取foo
的地址时,添加{{1}的偏移量在y
中,并使用“。即使struct Foo
也需要struct Foo foo;
的确切知识(并且,递归地,它由它组成的类型) - 生成的代码必须知道确切的struct Foo
以保留正确的字节数。堆?类似地,需要类型声明来知道哪些操作码用于数学(sizeof(struct Foo)
或iadd
或加法?必须扩展其中一个操作数,以及扩展到什么尺寸?),比较,步长大小时做指针算术(fadd
实际上添加了p + n
)等。这也阻止了访问不存在的成员(并且,通过扩展,将值传递给函数,然后遇到这个问题 - 即类型不匹配),但这更像是一个方便的副作用 - 编译器认为它是一个错误因为不知道要发出什么代码,而不是因为它认为程序员就像孩子一样必须被监视并保持秩序。
在汇编语言中(通常 - 就在昨天我读到微软研究院的一个项目,该项目为操作系统开发了一种类型化,可验证的汇编语言,可以安全地抵御某些建筑错误),你真的没有类型。你有字节。你从某个位置获取N个字节,为它们做一些东西,然后将它们存储到某个位置。是的,寄存器固定为某些字大小,有些可能用于特殊类型的值(例如,具有80位或更多位的专用浮点寄存器),但基本上,您可以在任何地方存储任何您喜欢的内容。没有人阻止你在某处存储8个字节,稍后只读取后4个字节并将它们与循环计数器一起添加以形成地址以存储返回值。
在其他语言中,类型系统更强大,同时允许更大范围的扩展,允许更高级别的编程,例如抽象出确切的类型(因此,它们的布局和打字),并采取任何类型的完整填充某个合同。它允许类型签名,例如n * sizeof(*p)
,这是一个包含任何类值的列表的函数(只要它是同源的,例如整数列表,字符串列表,a字符列表列表等)并返回其中一个元素,而不“删除”(例如转换为[a] -> a
)类型。 (根据实现,它实际上可能会生成多个实现,每个实现用于具有已知布局的单个类型,以提高性能 - 但这不会泄露给程序员。)
答案 1 :(得分:3)
关于类型及其编程价值,可以说很多。你在C中看到的甚至不是冰山一角。相反,它是一个肮脏的雪球,有人倾倒在冰山一角的尖端。 :)以下经典论文中的前几页解释了类型系统的一些基本优点:
http://www.lucacardelli.name/Papers/TypeSystems.pdf
让我添加两件事。
首先,输入的语言与要求(显式)类型声明之间存在差异。一些现代语言,尤其是来自功能阵营的现代语言,具有复杂的类型系统,但大多数时候都不需要你写下单一类型。所有类型都由编译器推断。
其次,类型系统本质上是一种逻辑。表示程序某些属性的逻辑,然后由编译器检查。原则上,这种逻辑的强大程度没有限制。 C是一个非常无聊的例子。在频谱的另一端是您可以使用的语言。表示排序列表的类型和排序函数的类型,以便函数只进行类型检查,看它是否实际上是排序算法的正确实现。显然,如果编译器能够像这样实际检查程序的正确性,它是非常有用的。然而,在类型系统的表现力和易用性之间存在权衡,因此在实践中,大多数主流语言最终都处于简单化的一面。但是特殊领域有时会从更复杂的类型系统中获益。
以下是CACM最近的一篇文章,讨论了功能语言OCaml中类型系统的优点(<其他内容]:
http://cacm.acm.org/magazines/2011/11/138203-ocaml-for-the-masses/
答案 2 :(得分:1)
是的,你几乎已经钉了它。打字只是一个方便的抽象。重要的是你如何使用原始位。键入有助于强制您以预期的方式使用这些位。
更新
在某种程度上,它可以通过消除一些常见错误来帮助确保程序的正确性
假设您有两个变量char var1 = 'a'
和int var2 = 10;
。如果您不小心尝试添加var1 + var2
,则键入的语言可能会生成错误。如果没有输入,它可能会很高兴地给你107
的结果并继续。可能很难跟踪107
的来源,直到您意识到a
的ASCII表示为97.
因此,在某种程度上,是的,它确保了您的计划的正确性。但显然还有许多其他错误(逻辑错误等),单独输入无法阻止或识别。
答案 3 :(得分:0)
... OR
更复杂的无类型语言可能会为您提供结果
'a' + 7
根据“+”运算符的定义,它可能根本不是错误。