首先跟進的問題,你的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
不用擔心每次都漏出字符串?無論如何,我認爲第二個論點有同樣的問題。 –