我非常清楚功能和命令式编程技术之间的区别.但是人们普遍倾向于谈论"功能语言",这真让我感到困惑.
当然,像Haskell这样的语言比C等其他语言对函数式编程更友好.但即便是前者也会进行I/O(它只是将它保存在贫民区).你可以用C编写功能程序(这简直太荒谬了).所以也许这只是程度问题.
尽管如此,即使是程度问题,当有人称Scheme为"功能语言"时,它意味着什么?我看到的大多数Scheme代码都是必不可少的.如果你愿意的话,只是Scheme可以很容易地用函数式编写吗?Lua和Python也是如此.它们也是"功能语言"吗?
我(真的)不想成为一名语言警察.如果这只是一种松散的谈话方式,那很好.我只想弄清楚它是否确实有一些确定的意义(即使这是一个程度问题),我没有看到.
这个问题是关于C标准需要什么,而不是主流编译器可以可靠地期望做什么.让我们关注C99,尽管有关C89/ANSI或C11如何分歧的输入也会受到欢迎.
第6.2.6.2节介绍了整数类型的"负0"的概念,它将0x8000...在使用整数的符号和幅度表示的0xFFFF...系统中,或者在使用一个补码表示的系统中.(该标准还允许此类系统将这些位模式用于陷阱值而不是负0;并且使用显性/更常见的二进制补码表示的系统没有负0.)
在该部分的进一步说,该标准说:
如果实现支持负零,则只能通过以下方式生成它们:
- 的
&,|,^,~,<<,和>>带参数的运算符产生这样的值- ...
未指定这些情况是否实际产生负零或正常零,以及当存储在对象中时负零是否变为正常零.
如果实现不支持负零的行为
&,|,^,~,<<,和>>运营商的参数会产生这样的价值是不确定的.
据我所知,标准没有进一步说明"产生这种价值的论据"的含义.但是,阅读本文的自然方式表明,任何类似于x | y您期望结果的操作0x8000...或0xFFFF...实际上符合标准的操作都具有未定义的行为.
咦?真?那么根据标准,即使在二进制补码机上,~0真的会导致不确定的行为吗?那疯狂.这不是预期的解释.
它们是否意味着:在使用符号和幅度或一个补码表示的系统上,并且没有负零,那么按位运算的行为将产生如果这些系统将为负零的位模式有一个未定义.在具有两个补码表示的系统上,此处的标准保持沉默?
如果你在标准中进一步展望(第6.5.7节),它会告诉我们:
uint32_t x = 1;
int32_t y = 1;
x << -1; /* is undefined, so is y << -1 */
x << 32; /* is …Run Code Online (Sandbox Code Playgroud) 我正在用MaybeUninitRust 和 FFI做一些似乎有效的事情,但我怀疑可能不健全/依赖于未定义的行为。
我的目标是让一个 structMoreA扩展一个 struct A,包括A作为初始字段。然后调用一些写入 struct 的 C 代码A。然后MoreA根据A.
在我的应用程序中, 的附加字段MoreA都是整数,因此我不必担心分配给它们的(未初始化的)先前值。
这是一个最小的例子:
use core::fmt::Debug;
use std::mem::MaybeUninit;
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(C)]
struct A(i32, i32);
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(C)]
struct MoreA {
head: A,
more: i32,
}
unsafe fn mock_ffi(p: *mut A) {
// write doesn't drop previous (uninitialized) occupant of p
p.write(A(1, 2));
}
fn main() {
let mut b = MaybeUninit::<MoreA>::uninit(); …Run Code Online (Sandbox Code Playgroud)