我最近阅读了Lua共同创作者Luiz H. de Figueredo和Roberto Ierusalimschy的采访,他们在那里讨论了Lua的设计和实现。至少可以说是非常有趣的。然而,讨论的一部分在我的脑海中带来了一些东西。 Roberto将Lua称为“独立应用程序”(也就是说,它是纯粹的ANSI C,它不使用操作系统。)他说,Lua的核心是完全可移植的,因为它的< em> pure 已经能够更容易地移植到甚至从未考虑过的平台(例如机器人和嵌入式设备)。
现在这让我很奇怪。 C一般来说是一种非常便携的语言。那么,C的哪些部分(即标准库中的部分)是最不可移植的?什么是可以预期在大多数平台上工作的?是否应该只使用一组有限的数据类型(例如,避免short
和float
)?那么FILE
和stdio
系统怎么样? malloc
和free
?似乎Lua避免了所有这些。这会把事情发挥到极致吗?或者它们是可移植性问题的根源?除此之外,还有什么其他方法可以使代码非常便携?
我问这一切的原因是因为我目前正在用纯C89编写一个应用程序,并且它最好尽可能便携。我愿意采取一条中间路来实现它(足够便携,但没有那么多,我必须从头开始编写所有内容。)无论如何,我只想看看编写最佳C代码的关键。
作为最后一点,所有这些讨论仅与C89有关。
答案 0 :(得分:13)
就Lua而言,我们没有太多抱怨C语言本身,但我们发现C标准库包含许多似乎无害且直接使用的功能,直到您认为它们为止不检查他们的输入有效性(如果不方便,这是好的)。 C标准说处理错误的输入是未定义的行为,允许这些函数做任何他们想做的事情,甚至崩溃主机程序。例如,考虑一下strftime。有些libc只是忽略无效的格式说明符,但其他libc(例如,在Windows中)崩溃!现在,strftime不是一个至关重要的功能。为什么崩溃而不是做一些明智的事情?因此,在调用strftime之前,Lua必须对输入进行自己的验证,并将strftime导出到Lua程序变成一件苦差事。因此,我们试图通过针对核心的独立性来清除Lua核心中的这些问题。但是Lua标准库不能这样做,因为他们的目标是将设施导出到Lua程序,包括C标准库中可用的内容。
答案 1 :(得分:9)
“Freestanding”在C的上下文中具有特定含义。大致上,独立主机不需要提供任何标准库,包括库函数malloc
/ free
,{{1某些标准标题仍然是必需的,但它们只定义了类型和宏(例如printf
)。
答案 2 :(得分:6)
C89允许两种类型的编译器:托管和独立。基本区别在于托管编译器提供了所有C89库,而独立编译器只需要提供<float.h>
,<limits.h>
,<stdarg.h>
和<stddef.h>
。如果您将自己限制在这些标题中,您的代码将可移植到任何 C89编译器。
答案 3 :(得分:4)
这是一个非常广泛的问题。我不会给出明确的答案,相反我会提出一些问题。
请注意,C标准将某些内容指定为“实现定义”;一致的程序将始终在任何符合要求的平台上编译并运行,但根据平台的不同,它可能会有不同的行为。具体来说,有
sizeof(long)
在一个平台上可能是四个字节,在另一个平台上可能是八个字节。 short
,int
,long
等的大小各有一定的最小值(通常相对于彼此),但除此之外没有任何保证。int a = 0xff00; int b = ((char *)&a)[0];
可以在一个平台上将0
分配给b
,在另一个平台上分配-1
。\0
始终是空字节,但其他字符如何显示取决于操作系统和其他因素。putchar('\n')
可以在一个平台上生成换行符,在下一个平台上生成回车符,并在每个平台上生成一个回合符。char
可能或者可能无法承担负值。各种字长和字节很常见。任何文本处理应用程序都可能出现字符编码问题。博物馆中最有可能找到9位字节的机器。这绝不是一份详尽的清单。
(请不要写C89,这是一个过时的标准.C99为可移植性添加了一些非常有用的东西,例如固定宽度整数int32_t
等。)
答案 4 :(得分:2)
任何属于C89标准的内容都应该可以移植到符合该标准的任何编译器。如果您坚持使用纯C89,您应该能够轻松地移植它。任何可移植性问题都可能是由于编译器错误或代码调用特定于实现的行为的地方。
答案 5 :(得分:2)
C的设计使得编译器可以编写为任何平台生成代码并调用它编译的语言“C”。这种自由与C相反,C是编写可在任何平台上使用的代码的语言。
任何为C编写代码的人都必须(有意或默认)决定他们支持的int
大小;虽然可以编写适用于任何合法大小int
的C代码,但它需要相当大的努力,并且生成的代码通常远不如为特定整数大小设计的代码可读。例如,如果一个变量x
的类型uint32_t
,并且希望将它乘以另一个y
,计算结果mod 4294967296,则语句x*=y;
将起作用在int
为32位或更小,或int
为65位或更大的平台上,但在Undefined Behavior
为33到64位的情况下将调用int
,并且如果操作数被视为整数而不是包含mod 4294967296的代数环的成员,那么该产品将超过INT_MAX
。通过将其重写为int
,可以使语句的工作独立于x*=1u*y;
的大小,但这样做会使代码不那么清晰,并且意外地从其中一个乘法中省略1u*
是灾难性的。
根据现行规则,如果代码仅用于整数大小与预期匹配的机器上,则C具有合理的可移植性。在int
大小与期望值不匹配的计算机上,代码不可能是可移植的,除非它包含足够的类型强制来使大多数语言的输入规则无关紧要。