2 回答

TA貢獻(xiàn)2051條經(jīng)驗(yàn) 獲得超10個(gè)贊
fts_open
定義如下:
fts_open()
該函數(shù)獲取指向一個(gè)字符指針數(shù)組的指針,這些指針命名一個(gè)或多個(gè)路徑,這些路徑構(gòu)成了要遍歷的邏輯文件層次結(jié)構(gòu)。數(shù)組必須由指針終止。fts_open()
null
C沒有對(duì)數(shù)組的直接支持;它只有指針。在你的情況下,你傳遞一個(gè)有效的指針,但它不在一個(gè)數(shù)組中,該數(shù)組有一個(gè)指針作為緊隨其后的元素,所以繼續(xù)掃描過去的內(nèi)存 - 尋找一個(gè)指針, 并最終嘗試在某個(gè)地址讀取內(nèi)存,這是禁止這樣做的(通常是因?yàn)樵摰刂返捻撁鏇]有被分配)。fts_open
NULL
fts_open
&path
NULL
修復(fù)它的一種方法是創(chuàng)建該數(shù)組并在C端初始化它。
看起來你正在使用一個(gè)相當(dāng)最新的C標(biāo)準(zhǔn),所以讓我們只使用直接文字來初始化數(shù)組:
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))
}
請(qǐng)注意,您的程序有一個(gè)錯(cuò)誤和一個(gè)可能的問題:
一個(gè)錯(cuò)誤是,調(diào)用通過從鏈接的 C 庫執(zhí)行調(diào)用來分配內(nèi)存塊,而您沒有釋放該內(nèi)存塊。
C.CString
malloc(3)
該符號(hào)定義在“標(biāo)準(zhǔn)定義.h”中;編譯時(shí)可能會(huì)或可能不會(huì)收到錯(cuò)誤。
NULL
我已經(jīng)在我的示例中修復(fù)了這兩個(gè)問題。
對(duì)我們的示例的進(jìn)一步改進(jìn)可能是利用函數(shù)在單次運(yùn)行中掃描多個(gè)路徑的能力;如果我們要實(shí)現(xiàn)它,那么為Go端的第一個(gè)參數(shù)分配數(shù)組會(huì)更有意義: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]))
}
請(qǐng)注意,這里我們沒有顯式地將最后一個(gè)參數(shù)清零,因?yàn)榕cC相反,Go用零初始化每個(gè)分配的內(nèi)存塊,因此一旦分配,其所有內(nèi)存都已歸零。argvargv

TA貢獻(xiàn)1811條經(jīng)驗(yàn) 獲得超6個(gè)贊
您收到錯(cuò)誤,因?yàn)椤癴ts_open”需要一個(gè)指向數(shù)組的字符指針,該數(shù)組以 NULL 結(jié)尾,如 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")))
}
因此添加數(shù)組指針將修復(fù)代碼。
使用 GCC 編譯時(shí),相同的代碼也有效,但fts_open返回 NULL。我猜gcc和cgo之間的優(yōu)化有一些區(qū)別(不是很確定)
我嘗試了一些測(cè)試結(jié)果,并能夠發(fā)現(xiàn),當(dāng)使用GCC編譯時(shí),字符**指針被空終止,但在cgo的情況下,它沒有以空值終止,所以你得到“SIGSEGV”,因?yàn)槟愕拇a正在讀取無效的內(nèi)存引用。
#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"))
}
相同的去代碼,你會(huì)面臨錯(cuò)誤
- 2 回答
- 0 關(guān)注
- 109 瀏覽
添加回答
舉報(bào)