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 关注
- 95 浏览
添加回答
举报