2 回答

TA貢獻2051條經驗 獲得超10個贊
fts_open
定義如下:
fts_open()
該函數獲取指向一個字符指針數組的指針,這些指針命名一個或多個路徑,這些路徑構成了要遍歷的邏輯文件層次結構。數組必須由指針終止。fts_open()
null
C沒有對數組的直接支持;它只有指針。在你的情況下,你傳遞一個有效的指針,但它不在一個數組中,該數組有一個指針作為緊隨其后的元素,所以繼續掃描過去的內存 - 尋找一個指針, 并最終嘗試在某個地址讀取內存,這是禁止這樣做的(通常是因為該地址的頁面沒有被分配)。fts_open
NULL
fts_open
&path
NULL
修復它的一種方法是創建該數組并在C端初始化它。
看起來你正在使用一個相當最新的C標準,所以讓我們只使用直接文字來初始化數組:
package main
/*
#include <stddef.h> // for NULL
#include <stdint.h>
#include <stdlib.h> // for C.free
#include <fts.h>
#include <sys/stat.h>
uintmax_t get_total_size(char *path)
{
uintmax_t total_size = 0;
char * path_argv[2] = {path, NULL};
FTS *fts = fts_open(path_argv, FTS_PHYSICAL, NULL);
FTSENT *fent;
while ((fent = fts_read(fts)) != NULL)
if (fent->fts_info == FTS_F)
total_size += fent->fts_statp->st_size;
fts_close(fts);
return total_size;
}
*/
import "C"
import (
"fmt"
"unsafe"
)
func main() {
cpath := C.CString("/usr")
defer C.free(unsafe.Pointer(cpath))
fmt.Println(C.get_total_size(cpath))
}
請注意,您的程序有一個錯誤和一個可能的問題:
一個錯誤是,調用通過從鏈接的 C 庫執行調用來分配內存塊,而您沒有釋放該內存塊。
C.CString
malloc(3)
該符號定義在“標準定義.h”中;編譯時可能會或可能不會收到錯誤。
NULL
我已經在我的示例中修復了這兩個問題。
對我們的示例的進一步改進可能是利用函數在單次運行中掃描多個路徑的能力;如果我們要實現它,那么為Go端的第一個參數分配數組會更有意義:fts_*
fts_open
package main
/*
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <fts.h>
#include <sys/stat.h>
uintmax_t get_total_size(char * const *path_argv)
{
uintmax_t total_size = 0;
FTS *fts = fts_open(path_argv, FTS_PHYSICAL, NULL);
FTSENT *fent;
while ((fent = fts_read(fts)) != NULL)
if (fent->fts_info == FTS_F)
total_size += fent->fts_statp->st_size;
fts_close(fts);
return total_size;
}
*/
import "C"
import (
"fmt"
"unsafe"
)
func main() {
fmt.Println(getTotalSize("/usr", "/etc"))
}
func getTotalSize(paths ...string) uint64 {
argv := make([]*C.char, len(paths)+1)
for i, path := range paths {
argv[i] = C.CString(path)
defer C.free(unsafe.Pointer(argv[i]))
}
return uint64(C.get_total_size(&argv[0]))
}
請注意,這里我們沒有顯式地將最后一個參數清零,因為與C相反,Go用零初始化每個分配的內存塊,因此一旦分配,其所有內存都已歸零。argvargv

TA貢獻1811條經驗 獲得超6個贊
您收到錯誤,因為“fts_open”需要一個指向數組的字符指針,該數組以 NULL 結尾,如 char *argv[] = { 路徑,NULL };.。(https://linux.die.net/man/3/fts_open)
package main
/*
#include <stdint.h>
#include <fts.h>
#include <sys/stat.h>
uintmax_t get_total_size(char *path)
{
uintmax_t total_size = 0;
char *argv[] = { path, NULL };
FTS *fts = fts_open(argv, FTS_PHYSICAL, NULL);
if (fts == NULL)
return 0;
FTSENT *fent;
while ((fent = fts_read(fts)) != NULL)
if (fent->fts_info == FTS_F)
total_size += fent->fts_statp->st_size;
fts_close(fts);
return total_size;
}
*/
import "C"
import "fmt"
func main() {
fmt.Println(C.get_total_size(C.CString("/usr")))
}
因此添加數組指針將修復代碼。
使用 GCC 編譯時,相同的代碼也有效,但fts_open返回 NULL。我猜gcc和cgo之間的優化有一些區別(不是很確定)
我嘗試了一些測試結果,并能夠發現,當使用GCC編譯時,字符**指針被空終止,但在cgo的情況下,它沒有以空值終止,所以你得到“SIGSEGV”,因為你的代碼正在讀取無效的內存引用。
#include <stdio.h>
#include <string.h>
void try(char **p)
{
while (*p != NULL)
{
printf("%zu\n", strlen(*p));
++p;
}
}
void get_total_size(char *path)
{
try(&path);
}
int main()
{
get_total_size("/usr");
}
c 代碼(有效)
package main
/*
#include <stdio.h>
#include <string.h>
void try(char **p)
{
while (*p != NULL)
{
printf("%zu\n", strlen(*p));
++p;
}
}
void get_total_size(char *path)
{
try(&path);
}
*/
import "C"
func main() {
C.get_total_size(C.CString("/usr"))
}
相同的去代碼,你會面臨錯誤
- 2 回答
- 0 關注
- 116 瀏覽
添加回答
舉報