Zig的介绍C程序员的整数铸造

2021-05-11 19:50:51

今天我们' ll只是谈论整数铸造,但Zig还为浮子,布尔,枚举,指针等提供了显式的铸造支持。有关显式演员的完整列表,请参阅https://ziglang.org/documentation/master/#explict -casts

在c中有两个主要问题 - 你不会' t始终知道它何时发生,而且你不会始终知道它是什么。一点是一个粗体索赔,但我的意思是C程序的纯文本分析(例如,通过{%C-Line%} Grep {%C-Line-end%}或{%C-Line% ctrl + f {%c-line-end%})找不到所有整数投压(由于隐式转换)和它确实发现的那些,没有文本方式来区分截断,重新诠释或扩展。

{%c-block语言=" c" %} #include< stdlib.h> int main(void){if(sizeof(int)< -1)abort();返回0; {%c-block-end%}

除非{%c-line%} - wextra {%c-line-end%}或{%c-line%} - weverything {%c-line-end%},否则您甚至会收到警告上。 ' s发生的是{%c-line%} - 1 {%c-line-end%}被隐式转换为unsigned(因为{%c-line%} sizeof {%c-line-终端%}是无符号),并导致大量数量。

ZIG通过1)消除了隐式转换,除非保证是安全的(例如,将{%C-Line%} U8 {%C-Line%}值分配给{%C-Line%} U16 {%C-Line-End%}变量不能失败或丢失数据)和2)为每个铸造操作员提供自己的内置功能,使其易于审核它们与简单的基于文本的工具一起使用。

{%C-Line%} @ as(){%c-line-end%}只允许在铸造操作是明确和安全的时,这意味着没有任何信息将被丢失,并且保证目标类型能够保持源类型。

{%c-block语言=" Zig" %} v x = 5; //不允许 - 应该签署x吗?无符号?什么尺寸? var x = @as(U8,5); //类型推断允许编译器确定x为键入U8 {%c-block-end%}

{%c-block语言=" Zig" %} var x:u8 = 5; var y = @as(i32,x); {%c-block-end%}

{%c-block语言=" Zig" %} var x:u8 = 5; var y = @as(u32,x); {%c-block-end%}

{%c-line%} @ truncate(){%c-line-end%}通过删除最有效的比特,用于显式地投射到具有相同符号的较小大小的整数。它'&#39等同于从较大符号的较大图中的显式c扩展的。

{%c-block语言=" Zig" %} var x = @as(U16,513); // x在二进制:0000001000000001 v v r = @truncate(u8,x); // y在二进制:00000001 {%c-block-end%}

警告:您可以在符号整数上调用{%c-line%} @ truncate(){%c-line-end%},但您需要确保您真正想要做的 - 自从{% c-line%} @ truncate {%c-line-end%}始终删除最高有效位,结果值可能会或可能不会为负,而不管原始值是否为负。

{%c-line%} @ bitcast {%c-line-end%}用于在与位弄置于相同大小的类型之间投射。换句话说,内存中的数据不会改变,但其解释可能。在整数铸造的上下文中,如果源值在目标类型的边界之外,则在符号和无符号类型之间投射时,这是相关的。例如,给定{%c-line%} u8 {%c-line-end%}值{%c-line%} 180 {%c-line-end%},则位覆盖器是{%c-line% 10110100 {%c-line-end%}。如果我们使用{%c-line%} @ bitcast {%c-line-end%}将此转换为{%c-line%} i8 {%c-line-end%}(假设2s补充符号),该值变为{%C-Line%} - 76 {%C-Line-End%}。但是,如果原始值为例如{%c-line-exp%}%c-line%} 100 {%c-line-end%},它仍然是{%c-line%} @ bitcast {%c-line-end%} {%c-line-end%} @ bitcast {由于{%C-LINE%} I8 {%C-LINE%} I8 {%C-LINE-END%}具有相同的位表示,因此C-Line-end%}具有相同的位表示。 {%C-LINE%} U8 {%C-LINE-END%}。

{%c-block语言=" Zig" %} var x = @as(U8,180); //二进制:10110100(值为180)var y = @bitcast(i8,x); //二进制:10110100(值为-76){%c-block-end%}

最后,我们有{%c-line%} @ intcast {%c-line-end%}。在某些方面{%C-Line%} @ intcast {%c-line-end%}是{%c-line%} @ bitcast {%c-line-end%}的双程 - 它在整数类型之间投射运行时,保留值但不一定是位替纳特。例如,{%c-line%} @ intcast {%c-line-end%}可用于转换{%c-%c-的%c-line%} i32 {%c-line-end%}值。 LINE%} 3 {%C-LINE-END%}至{%C-LINE%} U8 {%C-LINE-END%}。由于它并不总是可以执行此操作(例如 - {%C-Line%} U16 {%C-Line%} 0xFFFF {%C-Line-- END%}不能存储在{%C-LINE%} U8 {%C-LINE-END%})中{%C-LINE%} @ intcast {%C-Line-ex%}可以调用安全检查的未定义行为。换句话说,如果运行时安全处于活动状态(由于构建模式或{%C-Line%} @ setRuntimesAfetty(true){%c-line-end%}),则调用{%c-line%} @具有无效参数的intcast {%c-line-end%}将恐慌程序而不是在目标中留下意外值。如果关闭运行时安全,则会获得未定义的行为。

{%c-block语言=" Zig" %} // zig build-exe test.zig&& ./test pub fn main()void {var x = @as(i16,180); var y = @intcast(u8,x); //这是精细var z = @Intcast(i8,y); //这将崩溃} {%c-block-end%}

{%c-block语言="控制台" %}➜〜zig运行test.zig线程14280091恐慌:整数突出位/用户/ ehaas/test.zig:4:13:0x1018bf5bc在main(test)var z = @intcast(i8,y); ^ /users/ehaas/source/zig/build/lib/zig/std/start.zig:410:22:0x1010:22:0x1010c177c在std.start.callmain(test)root.main(); ^ /Users/ehaas/source/zig/build/lib/zig/std/start.zig:362:12:0x1018bf767在std.start.callmainwithargs(test)return @call(。{.modifier = .always_inline},callmain ,。{}); ^ /users/ehaas/source/zig/build/lib/zig/std/start.zig:332:12:0x1018bf6a5在std.start.main(test)return @call(。{.modifier = .always_inline},callmainwithargs ,。{@Intcast(USIZE,C_ARGC),C_ARGV,ENVP}); ^ ???:?:?:0x7FFF2032E620在??? (???)???:?:?:0x0在??? (???)[1] 79460 abort zig运行test.zig {%c-block-end%}

因此,当调用{%C-Line%} @ intcast {%c-line-ex%}时,您应该始终检查目标类型是否可以保存源值,除非您'重新确定值将适合。

如果你&#39怎么办?如果结果将适合,而且你不想每次添加或乘以检查吗?在这种情况下,你想要看到我们的下一篇文章,阻止在Zig中的整数溢出