首先跟进的问题,你的ToPtr
实施邀请不健全的代码。这里转载:
// code in italics is wrong
impl ToPtr for str {
fn to_ptr(&self) -> *const i8 {
CString::new(self).unwrap().as_ptr()
}
}
这种分配一个新CString
,并返回一个指向它的内容,但CString
时to_ptr
收益下降,所以这是一个悬摆指针。 该指针的任何解引用都是未定义的行为。documentation对此有一个很大的警告,但它仍然是一个非常常见的错误。
从字符串文字生成*const c_char
的一个正确方法是b"string here\0".as_ptr() as *const c_char
。该字符串以null结尾,并且没有悬挂指针,因为字符串文字在整个程序中都存在。如果你有一个非常要转换的字符串,你必须保持的CString
活着正在使用它时,就像这样:
let s = "foo";
let cs = CString::new(s).unwrap(); // don't call .as_ptr(), so the CString stays alive
unsafe { some_c_function(cs.as_ptr()); }
// CString is dropped here, after we're done with it
旁白:编辑“建议”(我新堆栈溢出,但它似乎更有礼貌发表评论,而不是试图重写我的答案),上面的代码可以这样写:
let s = "foo";
unsafe {
// due to temporary drop rules, the CString will be dropped at the end of the statement (the `;`)
some_c_function(CString::new(s).unwrap().as_ptr());
}
尽管这在技术上是正确的(最好的一种正确的),涉及的“临时放置规则”很微妙 - 这工作,因为as_ptr
需要到CString
引用(实际上是一个& CStr的,因为编译器改变方法链的CString ::新(S).unwrap()DEREF()as_ptr()。)而不是消耗它,并且因为我们只有一个C函数可以调用。编写不安全代码时,我不喜欢依赖任何细微或不明显的东西。
有了这样的方式,我fixed that unsoundness在你的代码(您的通话都使用字符串文字,所以我只是用我上面的第一个策略)。我在OSX上得到这个输出:
0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 0
0, 0, 8, 2, 0, 0, 0, 0, 0, 0, 0
0, 0, 4, 3, 0, 0, 0, 0, 0, 0, 0
所以,这符合你的结果吧?我也写了下面的C程序:
#include <stdio.h>
#include <unistd.h>
int main() {
struct __sFILE *fp1 = fdopen(STDIN_FILENO, "r");
struct __sFILE *fp2 = fdopen(STDOUT_FILENO, "w");
struct __sFILE *fp3 = fdopen(STDERR_FILENO, "w");
struct __sFILE *passwd = fopen("/etc/passwd", "r");
printf("%i %i %i %i\n", fp1->_flags, fp2->_flags, fp3->_flags, passwd->_flags);
}
,并得到了输出:
4 8 8 4
这似乎证实了这项防锈效果。有在/usr/include/stdio.h
顶部写着评论:
/*
* The following always hold:
*
* if (_flags&(__SLBF|__SWR)) == (__SLBF|__SWR),
* _lbfsize is -_bf._size, else _lbfsize is 0
* if _flags&__SRD, _w is 0
* if _flags&__SWR, _r is 0
*/
仰起脸这些常量:
#define __SLBF 0x0001 /* line buffered */
#define __SRD 0x0004 /* OK to read */
#define __SWR 0x0008 /* OK to write */
这似乎是我们得到的输出相匹配:4在读模式打开的文件,8写。那么这里有什么问题?
您发布的代码不会编译(我认为fp和passwd混淆了)。另外,你传递给C函数的字符串不是NUL终止的,所以你的代码有完全未定义的行为。 –
哦,是的,我忘了添加一个NUL终止的文件,我已经更新了上面的要点 – hansaplast
不用担心每次都漏出字符串?无论如何,我认为第二个论点有同样的问题。 –