我目前正在与seek
进行一场小型战斗,并在32位(x86)盒子上运行C程序。
具体来说,我似乎无法寻求超越看似相当随意的文件偏移量。
如果我这样做:
unsigned long long pos = 15032385535LLU;
int r = fseek(fd, pos, SEEK_SET);
然后我会得到
fstat64(3, {st_mode=S_IFREG|0644, st_size=1000000000000, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77c3000
_llseek(3, 2147479552, [2147479552], SEEK_SET) = 0
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4095) = 4095
TL; DR 它有效。
但是,如果我通过 1 增加pos
...
unsigned long long pos = 15032385536LLU;
int r = fseek(fd, pos, SEEK_SET);
......然后一切都崩溃了:
fstat64(3, {st_mode=S_IFREG|0644, st_size=1000000000000, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb771e000
_llseek(3, 18446744071562067968, 0xbfd0f5f8, SEEK_SET) = -1 EINVAL (Invalid argument)
我完全迷失了原因。我做错了什么?
我能想到的唯一重要花絮是15032385535
37FFFFFFF
似乎很有趣,以及数字seems to be related to time wraparound。
有问题的程序正在使用-D_FILE_OFFSET_BITS=64
进行编译,事实证明这对我实际开放的大型文件实际上是有帮助的,但似乎并没有在这里产生有用的差异。我偶然发现-DLARGEFILES -D_LARGEFILE_SOURCE
并尝试添加,但似乎没有任何明显的效果。
对于上下文(因为琐事很有趣):我使用truncate
创建了一个大型稀疏文件,以便在一台单独的32位计算机上(完美地)重现该问题;有问题的程序是一个小型的网络服务器 - 我正在尝试从备用计算机上复制一些数据,而且我发现令人惊讶很难找到一个可以处理的紧凑型Web服务器{{ 1}}请求和同时下载。 nginx抛出Perl错误我不打算调查(Slackware打包问题 - 不行),Python的SimpleHTTPServer简单无用,并且thttpd溶解成一堆mmap错误。有趣的一天...
答案 0 :(得分:5)
如果用十六进制(或二进制)编写数字,则更容易理解。
15032385535 = 0x37fffffff
15032385536 = 0x380000000
在您的系统上,unsigned long long
是32位类型,fseek
是64位类型。
long
的第二个参数的类型为unsigned long long pos = …;
int r = fseek(fd, pos, SEEK_SET);
。当你写
unsigned long long
将第二个参数的值转换为必需类型。将无符号整数类型转换为较小的整数类型 - 此处为unsigned long
到fseek(fd, pos & 0xffffffff, SEEK_SET)
- 当值溢出较小的类型时具有未定义的行为,但在大多数平台上,包括您的平台,它会截断最重要的位价值。它相当于
0xffffffff
因为unsigned long
是pos = 0x37fffffff
的最大值。当fseek
时,结果值为0x7fffffff = 2147483647.请注意,对pos = 0x380000000
的调用实际上不起作用!它没有寻求你认为你要求的职位。
当_llseek
时,会发生另一种现象:设置截断值中最重要的位,并将其用作符号位,因为您的计算机(与大多数计算机一样)使用two's complement表示形式为负数数字。因此得出的值是负的;它是-0x80000000 = -2147483648。然后将此负值传递给系统调用long
,该调用采用64位值(即使在32位系统上)。它收到的值是-0x80000000,strace显示为二进制补码无符号对应的64位数字 - 18446744071562067968 = 0xffffffff80000000。
使用标准C,您无法使用超出fseeko
范围的位置搜索文件。如果您愿意依赖POSIX函数,则fseek
与off_t
类似,但采用long
类型的第二个参数而不是-D_FILE_OFFSET_BITS=64
。在off_t
下,ProgressDialog progress = new ProgressDialog(getApplicationContext());
progress.setTitle("In Progress");
progress.show();
AsyncTask.execute(new Runnable() {
@Override
public void run() {
//Do things.
runOnUiThread(new Runnable() {
@Override
public void run() {
//Update UI.
}
});
//Do things.
runOnUiThread(new Runnable() {
@Override
public void run() {
progress.dismiss();
}
});
}
});
progress.setOnDismissListener(newDialogInterface.OnDismissListener()
{
@Override
public void onDismiss(DialogInterface dialogInterface) {
//Called after your background task ended.
}
});
是64位类型。