ftruncate() 总是精确的吗?
Is ftruncate() always precise?
我正在尝试 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 内容为:
The truncate() and ftruncate() functions cause the regular file named by path or referenced by fd to be truncated to a size of precisely length bytes.
尽管如此,POSIX specification 并不具体(双关语):
If fildes refers to a regular file, the ftruncate() function shall cause the size of the file to be truncated to length. [...] If the file previously was smaller than this size, ftruncate() shall increase the size of the file.
这是否意味着 ftruncate
总是将长度设置为恰好指定的字节数?如果确实如此,则意味着 macOS X Big Sur 不 完全 POSIX 兼容 (即使它被证明是这样)。如果不是,我如何保证它会将 fd
截断为我想要的大小?
简而言之,您无法保证 共享内存对象 的大小与您要求 ftruncate
的大小完全相同。这是因为,正如 @user3386109 所说,“您引用的 POSIX 规范部分以“If fildes 引用常规文件”开头”。 =25=].
如果您想将自己限制在任意长度,您始终可以使用辅助变量来跟踪您假设的大小(即使实际大小可能实际上不同,这可能并不那么重要毕竟)。您的代码如下所示:
#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 共享内存对象来跟踪你假设它的大小跨越他们。
我正在尝试 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 内容为:
The truncate() and ftruncate() functions cause the regular file named by path or referenced by fd to be truncated to a size of precisely length bytes.
尽管如此,POSIX specification 并不具体(双关语):
If fildes refers to a regular file, the ftruncate() function shall cause the size of the file to be truncated to length. [...] If the file previously was smaller than this size, ftruncate() shall increase the size of the file.
这是否意味着 ftruncate
总是将长度设置为恰好指定的字节数?如果确实如此,则意味着 macOS X Big Sur 不 完全 POSIX 兼容 (即使它被证明是这样)。如果不是,我如何保证它会将 fd
截断为我想要的大小?
简而言之,您无法保证 共享内存对象 的大小与您要求 ftruncate
的大小完全相同。这是因为,正如 @user3386109 所说,“您引用的 POSIX 规范部分以“If fildes 引用常规文件”开头”。 =25=].
如果您想将自己限制在任意长度,您始终可以使用辅助变量来跟踪您假设的大小(即使实际大小可能实际上不同,这可能并不那么重要毕竟)。您的代码如下所示:
#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 共享内存对象来跟踪你假设它的大小跨越他们。