stafs 结构的元素返回负值

Negative values returned by stafs struct's elements

我正在尝试检索安装在我的 Linux 系统上的外部 SD 卡的文件系统信息(使用 C 程序)。

根据statfsbits/statfs.h

中的定义
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
~$

mountdf 的输出是:

~$ 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 代码有什么问题?

您的代码存在问题,您正在尝试打印 long int 而不是 unsigned long int。您需要按如下方式更改 printf 语句:

printf("Total size of %s: %lu\n", argv[1], total);
printf("Total free space: %lu\n", available);

代码还有一个问题。

__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,请考虑更宽的类型并确保乘法也很宽。这将减少 overflow/narrowing.

的可能性
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);