微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ftruncate() 总是精确的吗?

如何解决ftruncate() 总是精确的吗?

我正在尝试 ftruncate 一个特定长度的共享内存对象。例如,我想使用以下代码段将其长度设置为 1 个字节:

#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>

int main() {
    struct stat fd_stat;
    int fd;

    fd = shm_open("NAME",O_RDWR | O_CREAT,S_IRUSR | S_IWUSR);
    fstat(fd,&fd_stat);

    printf("Size before: %lld\n",fd_stat.st_size);

    ftruncate(fd,1);
    fstat(fd,&fd_stat);

    printf("Size after: %lld\n",fd_stat.st_size);
}

在 Ubuntu 20.04 中打印:

Size before: 0
Size after: 1

这是我期望的输出

但是,在 macOS X Big Sur 中,我得到:

Size before: 0
Size after: 4096

如您所见,它似乎将大小扩展到页面大小。

ftruncate Linux man page 读作:

truncate() 和 ftruncate() 函数导致由 path 命名或由 fd 引用的常规文件被截断为大小精确长度字节。。 >

尽管如此,POSIX specification 并不具体(双关语):

如果 fildes 引用常规文件,则 ftruncate() 函数将导致文件的大小被截断为长度。 [...] 如果之前的文件小于这个大小,ftruncate() 应该增加文件的大小

这是否意味着 ftruncate 总是将长度设置为恰好指定的字节数?如果确实如此,则意味着 macOS X Big Sur 不完全符合 POSIX(即使它已被证明如此)。如果没有,我如何保证它会将 fd 截断为我想要的大小?

解决方法

简而言之,您无法保证您的共享内存对象的大小正好符合您要求的 ftruncate 大小。这是因为,正如@user3386109 所说,“您引用的 POSIX 规范部分以“If fildes 引用常规文件””开头。

如果你想把自己限制在任意长度,你总是可以使用一个辅助变量来跟踪你假设的大小(即使实际大小可能实际上不同,毕竟这可能并不那么重要)。您的代码如下所示:

#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>

int main() {
    struct stat fd_stat;
    int fd;
    off_t fd_size;

    fd = shm_open("NAME",O_RDWR | O_CREAT,S_IRUSR | S_IWUSR);
    fstat(fd,&fd_stat);

    printf("Size before: %lld\n",fd_stat.st_size);

    fd_size = 1;

    ftruncate(fd,fd_size);
    fstat(fd,&fd_stat);

    printf("Actual size: %lld\n",fd_stat.st_size);
    printf("Perceived size: %lld\n",fd_size);
}

最重要的是,如果您想在不同进程之间共享大小,可以将 fd_size 转换为 mmap ed 共享内存对象,以跟踪您假设它跨越的大小他们都是。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。