我正在尝试检索安装在我的Linux系统上的外部SD卡的文件系统信息(带有C程序)。
根据 bits / statfs.h
中 statfs 的定义struct statfs
{
__SWORD_TYPE f_type;
__SWORD_TYPE f_bsize;
#ifndef __USE_FILE_OFFSET64
__fsblkcnt_t f_blocks;
__fsblkcnt_t f_bfree;
__fsblkcnt_t f_bavail;
__fsfilcnt_t f_files;
__fsfilcnt_t f_ffree;
#else
__fsblkcnt64_t f_blocks;
__fsblkcnt64_t f_bfree;
__fsblkcnt64_t f_bavail;
__fsfilcnt64_t f_files;
__fsfilcnt64_t f_ffree;
#endif
__fsid_t f_fsid;
__SWORD_TYPE f_namelen;
__SWORD_TYPE f_frsize;
__SWORD_TYPE f_flags;
__SWORD_TYPE f_spare[4];
};
我写了这个小例子:
#include <stdio.h>
#include <stdlib.h>
#include <sys/statfs.h>
int main(int argc, const char *argv[])
{
struct statfs buffer;
unsigned long int total = 0;
unsigned long int available = 0;
statfs(argv[1], &buffer);
total = buffer.f_blocks * buffer.f_frsize;
available = buffer.f_bavail * buffer.f_frsize;
printf("Total size of %s: %ld\n", argv[1], total);
printf("Total free space: %ld\n", available);
return 0;
}
但是当代码执行时,我总是检索负值:
~$ ./fsStat /media/E4AD-87E9
Total size of /media/E4AD-87E9: -637362176
Total free space: -637366272
~$
mount 和 df 的输出为:
~$ mount
/dev/mmcblk0p1 on /media/E4AD-87E9 type vfat (rw,nosuid,nodev,relatime,uid=1000,gid=1000,fmask=0022,dmask=0077,codepage=cp437,iocharset=utf8,shortname=mixed,showexec,utf8,flush,errors=remount-ro,uhelper=udisks)
~$ df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/mmcblk0p1 7766184 4 7766180 1% /media/E4AD-87E9
我的C代码出了什么问题?
答案 0 :(得分:3)
您的代码存在的问题是您尝试打印long int
而不是unsigned long int
。您需要更改printf
语句,如下所示:
printf("Total size of %s: %lu\n", argv[1], total);
printf("Total free space: %lu\n", available);
答案 1 :(得分:0)
代码有另一个问题。
__fsblkcnt_t
不是标准类型,没有printf()
说明符。至少在一个place中,它是64位无符号。
OP的代码可以通过分配更窄的类型进行限制,因为unsigned long
只能确定至少有32位。
unsigned long int total = 0;
...
// Multiplication could overflow
// Assigment could narrow the product
total = buffer.f_blocks * buffer.f_frsize;
在代码不确定类型范围__fsblkcnt_t
的地方,考虑更宽的类型并确保乘法也很宽。这将减少溢出/缩小的可能性。
unsigned long long total = 0;
...
total = 1ULL * buffer.f_blocks * buffer.f_frsize;
// use u for unsigned types, not d
printf("Total size of %s: %llu\n", argv[1], total);
为了好玩,考虑到Moore's law,外部SD卡的total
大小将在2075年左右超过64位.YMMV
代码可以使用uintmax_t
代替unsigned long long
并检测产品溢出。 IMO uintmax_t
通常会在十年左右超过64位。
#include <inttypes.h>
uintmax_t total;
...
if (UINTMAX_MAX/buffer.f_blocks >= buffer.f_frsize)
total = UINTMAX_MAX;
else
total = UINTMAX_C(1) * buffer.f_blocks * buffer.f_frsize;
// use j with intmax_t/uintmax_t
printf("Total size of %s: %ju\n", argv[1], total);