什么是替代品可供前身 - 广泛支持的行为不是由C标准定义 [英] What replacements are available for formerly-widely-supported behaviors not defined by C standard

查看:196
本文介绍了什么是替代品可供前身 - 广泛支持的行为不是由C标准定义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C之前标准化初期,实现了多种处理各种行动的特殊和半特殊情况下的方式。他们中的一些会触发陷阱,如果不先配置可能导致随机code执行。因为这种陷阱的行为是C标准的范围之内(可能在某些情况下,由操作系统正在运行的程序的控制范围之外进行控制),并避免要求编译器不会允许code这一直依赖于这样的陷阱,继续这样做,那可能会导致这些陷阱动作行为完全取决于编译器/平台的自由裁量权。

In the early days of C prior to standardization, implementations had a variety of ways of handling exceptional and semi-exceptional cases of various actions. Some of them would trigger traps which could cause random code execution if not configured first. Because the behavior of such traps was outside the scope of the C standard (and may in some cases be controlled by an operating system outside the control of the running program), and to avoid requiring that compilers not allow code which had been relying upon such traps to keep on doing so, the behavior of actions that could cause such traps was left entirely up to the discretion of the compiler/platform.

到了90年代末,虽然由C标准没有要求这样做,每一个主流的编译器已经通过了很多这些情况常见行为;使用这样的行为将允许相对于code速度,大小和可读性的改进。

By the end of the 1990s, although not required to do so by the C standard, every mainstream compiler had adopted common behaviors for many of these situations; using such behaviors would allow improvements with respect to code speed, size, and readability.

由于请求以下操作的明显的方式不再受支持,人们应该如何去以这样的方式取代它们,以不妨碍可读性,也不使用旧的编译器时code一代产生不利影响?有关说明的目的,假设 INT 是32位的, UI 是一个无符号整数, SI 签订int和 b 是无符号的字符。

Since the "obvious" ways of requesting the following operations are no longer supported, how should one go about replacing them in such a way as to not impede readability nor adversely affect code generation when using older compilers? For purposes of descriptions, assume int is 32-bit, ui is a unsigned int, si is signed int, and b is unsigned char.


  1. 由于 UI B ,计算 UI<< b 对B == 0..31或可任意表现为 UI℃的价值;< (二及31条)或值32..255为零。请注意,如果左边的操作数是零,每当右手操作数超过31,这两个行为将是相同的。

  1. Given ui and b, compute ui << b for b==0..31, or a value which may arbitrarily behave as ui << (b & 31) or zero for values 32..255. Note that if the left-hand operand is zero whenever the right-hand operand exceeds 31, both behaviors will be identical.

有关code只需要能够产生零在处理器上运行时右移或左移的量从32到255,计算 UI&所述;&下; b 对B == 0..31 0对B == 32..255。虽然编译器可能能够优化了旨在跳过值32..255移位(所以code将简单地执行,将产生正确的行为的转变)条件逻辑,我不知道有什么办法制定这样的条件逻辑,将保证编译器不会产生不必要的code吧。

For code that only needs to run on a processor that yields zero when right-shifting or left-shifting by an amount from 32 to 255, compute ui << b for b==0..31 and 0 for b==32..255. While a compiler might be able to optimize out conditional logic designed to skip the shift for values 32..255 (so code would simply perform the shift that will yield the correct behavior), I don't know any way to formulate such conditional logic that would guarantee the compiler won't generate needless code for it.

与图1和2,但对于右移

As with 1 and 2, but for right shifts.

由于 SI B 这样b0..30和 SI *(1 LT;&LT; b)不会溢出,计算 SI *(1 LT;&LT; b)。注意,使用乘法运算符将严重损害许多老的编译器的性能,但如果偏移的目的是按比例绘制一个符号值,转换为在例无符号,其中贯穿变速感觉错误操作数将保持负

Given si and b such that b0..30 and si*(1<<b) would not overflow, compute si*(1<<b). Note that use of the multiplication operator would grossly impair performance on many older compilers, but if the purpose of the shift is to scale a signed value, casting to unsigned in cases where the operand would remain negative throughout shifting feels wrong.

鉴于各种整数值,执行加法,减法,乘法,以及变化,这样的方式,如果没有溢出的结果将是正确的,并且如果有溢出code要么产生的值,其高位表现在非捕获和非UB但其他不确定的时尚或将捕获的识别的平台定义的方式(和不支持的陷阱,只会产生不确定的价值平台)。

Given various integer values, perform additions, subtractions, multiplications, and shifts, such fashion that if there are no overflows the results will be correct, and if there are overflows the code will either produce values whose upper bits behave in non-trapping and non-UB but otherwise indeterminate fashion or will trap in recognizable platform-defined fashion (and on platforms which don't support traps, would simply yield indeterminate value).

由于一个指向分配的区域,并在其中一些指针的东西,使用的realloc 来更改分配大小,调整上述指针相匹配,而避免的情况下额外的工作,其中的realloc 返回原来的块。在所有平台上并不一定可行的,但20世纪90年代主流平台都会让code,以确定是否的realloc 引起事物的运动,并确定什么样的偏移指针进入以前是通过减去该对象的前基地址死对象(注意该调整需要通过计算与每个死指针相关的偏移量,然后将其添加新的指针来完成的,而不是试图通过计算新旧指针之间的差异化 - 东西会很多分段架构合法失败)

Given a pointer to an allocated region and some pointers to things within it, use realloc to change the allocation size and adjust the aforementioned pointers to match, while avoiding extra work in cases where realloc returns the original block. Not necessarily possible on all platforms, but 1990s mainstream platforms would all allow code to determine if realloc caused things to move, and determine the what the offset of a pointer into a dead object used to be by subtracting the former base address of that object (note that the adjustment would need to be done by computing the offset associated with each dead pointer, and then adding it the new pointer, rather than by trying to compute the "difference" between old and new pointers--something that would legitimately fail on many segmented architectures).

做超现代的编译器提供这不会降低code尺寸,速度,还是可读性的至少一个以上的良好替代品,而在任何其他人提供没有改善?从我可以告诉,不仅可以在整个20世纪90年代的编译器的99%做所有上述情况,但每个例如,一个本来可以写code以同样的方式上几乎所有的。一些编译器可能试图优化左移和右移与一不留神跳表,但是这是我能想到的,其中一个20世纪90年代编译器的1990平台将有编码的明显的方式有问题的唯一案例任何上述的。如果超现代编译器已不再支持经典的形式,有什么事他们提供作为替代品?

Do "hyper-modern" compilers provide any good replacements for the above which would not degrade at least one of code size, speed, or readability, while offering no improvements in any of the others? From what I can tell, not only could 99% of compilers throughout the 1990s do all of the above, but for each example one would have been able to write the code the same way on nearly all of them. A few compilers might have tried to optimize left-shifts and right-shifts with an unguarded jump table, but that's the only case I can think of where a 1990s compiler for a 1990s platform would have any problem with the "obvious" way of coding any of the above. If that hyper-modern compilers have ceased to support the classic forms, what do they offer as replacements?

推荐答案

现代标准C以这样一种方式,它可以保证为可移植的,如果的且仅当的你写你的$ C指定有关底层硬件没有更多的期待$ C它将运行比是由C抽象机的标准含蓄,并明确说明给出。

Modern Standard C is specified in such a way that it can be guaranteed to be portable if and only if you write your code with no more expectations about the underlying hardware it will run on than are given by the C abstract machine the standard implicitly and explicitly describes.

您还可以写,在一个给定的目标CPU和建筑给定的优化级别都有具体行为具体的编译器,但随后的的指望任何其他编译器(现代或以其他方式,甚至你写的)的次要修订走出去的方式,试图凭直觉你的期望,如果你的code违反那里的标准说,这是不合理的任何明确的实施无关的行为的条件。

You can still write for a specific compiler that has specific behaviour at a given optimization level for a given target CPU and architecture, but then do not expect any other compiler (modern or otherwise, or even a minor revision of the one you wrote for) to go out of its way to try to intuit your expectations if your code violates conditions where the Standard says that it is unreasonable to expect any well defined implementation agnostic behaviour.

这篇关于什么是替代品可供前身 - 广泛支持的行为不是由C标准定义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆