为啥 Rust 函数和 FFI C++ 函数以相反的顺序执行?

Posted

技术标签:

【中文标题】为啥 Rust 函数和 FFI C++ 函数以相反的顺序执行?【英文标题】:Why do a Rust function and a FFI C++ function execute in reverse order?为什么 Rust 函数和 FFI C++ 函数以相反的顺序执行? 【发布时间】:2018-03-25 11:13:09 【问题描述】:

我尝试将外部 C++ 函数与我的 Rust 应用程序链接。此函数有效,但执行顺序与从 Rust 代码中调用的顺序不同。

为什么会这样?这有记录吗?

这里是 Rust 应用程序的列表:

extern crate libc;
use libc::c_int;

#[link(name = "Project1", kind = "static")]
extern "C" 
    pub fn lib_fun(i: c_int) -> c_int;


fn main() 
    unsafe 
        lib_fun(2);
    
    println!("from Rust: ", 2);

“Project1”库如下所示:

#include <stdio.h>

extern "C" 
    int lib_fun(int t) 
        printf("from C++: %d\n", t);
        return t;
    

预期输出:

from C++: 2
from Rust: 2

真正的输出是相反的顺序:

from Rust: 2
from C++: 2

外部函数lib_func是否在另一个线程中执行?为什么?

详情:

平台:Windows 7、x64、 Rust:1.26.0(每晚), C++:Microsoft Visual Studio Community 2017 Preview 15.7.0 Preview 2.0 终端:IntelliJ IDEA 的集成终端。

【问题讨论】:

绝对不是 threading (Rust 不会在你背后创建线程),所以我怀疑你在 stdout 上运行缓冲;这很奇怪,因为我认为在格式字符串中使用\n 会导致printf 立即刷新。 尝试在 C++ 中手动刷新stdout @Veedrac 谢谢。我在 C++ 函数的末尾添加了fflush(stdout);,事情就按正确的顺序发生了。 我无法在 Arch Linux x64 上使用 rustc 1.24.1 和 GCC 7.3.1 重现此问题。您使用的是哪个 C++ 编译器和哪个版本的 Rust? @Michail:我不认为 Rust 是这里的问题,我怀疑你的 C++ 实现是。您使用的是哪个 C++ 编译器?视觉工作室? (哪个版本?)还是别的什么? 【参考方案1】:

外部 C++ 代码使用自己的缓冲区写入标准输出,并且比 Rust 调用者更晚刷新到系统缓冲区。 printf("...\n") 没有像我预期的那样刷新标准输出缓冲区。

相反,我需要手动刷新它,例如通过调用 fflush(stdout);

Thanks for this answer to @Veedrac

【讨论】:

这并不是普遍适用的。在带有 Clang (Apple LLVM version 9.0.0 (clang-900.0.39.2)) 的 macOS 10.13.3 上,输出的顺序正确。在 Windows 10 上使用 Visual Studio 2017 时,该顺序也是正确的。这取决于平台标准库的实现细节——它应该printf 中有换行符时刷新。 printf 的文档根本没有提到刷新。 我在***.com/questions/49475166/… 找到的这篇文章据我了解可能与\n 刷新但不应该。可能取决于操作系统和/或 C++ 编译器。 刷新行为通常随isatty(fileno(stdout)) 而变化。因此,相同的操作系统、相同的代码、相同的编译器、相同的二进制文件,可以根据调用二进制文件的方式而具有不同的缓冲行为。

以上是关于为啥 Rust 函数和 FFI C++ 函数以相反的顺序执行?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 FFI 函数的第二次调用无法匹配字符串比较?

如何从 NodeJS 中的 Rust FFI 函数返回字符串值?

通过 FFI 调用 Rust 函数时访问冲突

如何将 Lua FFI 与 C++ 函数一起使用

如何使用字符串作为参数从 Go 调用 Rust 函数?

从 Rust 调用动态链接的 Haskell 代码