我的观点是,如果由于需要能够保存或(-1)的任何可能值,C实现不能满足某些stdio函数(特别是fputc/ fgetc)的规范.这个推理是否正确?sizeof(int)==1intunsigned charEOF
(显然sizeof(int)不能为1,如果CHAR_BIT是8,由于所需的最小范围int,所以我们隐含地仅讨论与CHAR_BIT>=16例如DSP的实现,其中典型的实现将是独立实现而不是托管实现,因此不需要提供stdio.)
编辑:在阅读了答案和一些链接引用后,对托管实现可能有效的方式有一些想法sizeof(int)==1:
首先,一些引用:
7.19.7.1(2-3):
如果未设置stream指向的输入流的结束指示符并且存在下一个字符,则fgetc函数将该字符作为转换为int的unsigned char获取并为该流提前关联的文件位置指示符(如果定义).
如果设置了流的结束指示符,或者流处于文件结尾,则设置流的结束指示符并且fgetc函数返回EOF.否则,fgetc函数返回stream指向的输入流中的下一个字符.如果发生读取错误,则设置流的错误指示符,并且fgetc函数返回EOF.
7.19.8.1(2):
fread函数在ptr指向的数组中,从stream指向的流中读取大小由size指定的nmemb元素.对于每个对象,对fgetc函数进行大小调用,并按顺序读取存储在unsigned char数组中的结果,该数组恰好覆盖对象.流的文件位置指示符(如果已定义)按成功读取的字符数提前.
思考:
读回unsigned char范围之外的值int可能只是在实现中具有未定义的实现定义的行为.这是特别令人不安,因为它意味着使用fwrite和fread存储二进制结构(这同时导致不可移植的文件,应该是你可以在任何单个实现便携执行操作)可能出现的工作只是默默地失败.基本上总是导致未定义的行为.我接受的实现可能没有一个可用的文件系统,但它的很多难以接受的实现可以有一个文件系统,当你试图用它那就会自动调用鼻鬼,没有办法判断它的不可用. 现在,我意识到行为是实现定义的,而不是不确定的,它不是这么不安,我想这可能是一个有效的(虽然不受欢迎)的实现.
实现sizeof(int)==1可以简单地将文件系统定义为空且只读.然后,就没有办法应用程序可以读取本身写的,只从一个输入设备的任何数据stdin可能被实现为只给予积极的char配合在价值观int.
编辑(再次):从C99理由,7.4:
EOF传统上是-1,但可以是任何负整数,因此可以与任何有效的字符代码区分开.
这似乎表明sizeof(int)可能不是1,或者至少这是委员会的意图.
CB *_*ley 24
实现可以满足接口要求fgetc,fputc甚至可以满足接口要求sizeof(int) == 1.
该接口fgetc表示它返回读取为unsigned char转换为的字符int.没有任何地方说这个值是不可能的,EOF尽管期望显然有效读数"通常"返回正值.当然,fgetc返回EOF读取失败或流结束但在这些情况下还会设置文件的错误指示符或文件结束指示符(分别).
同样地,无处它说,你不能传递EOF到fputc只要恰好与价值相一致unsigned char转换为一个int.
显然程序员必须在这样的平台上非常小心.这可能不是完整的副本:
void Copy(FILE *out, FILE *in)
{
int c;
while((c = fgetc(in)) != EOF)
fputc(c, out);
}
Run Code Online (Sandbox Code Playgroud)
相反,你必须做类似的事情(未经测试!):
void Copy(FILE *out, FILE *in)
{
int c;
while((c = fgetc(in)) != EOF || (!feof(in) && !ferror(in)))
fputc(c, out);
}
Run Code Online (Sandbox Code Playgroud)
当然,平台,在这里你将有真正的问题是那些sizeof(int) == 1从转换unsigned char到int不注射.我认为,对于使用符号和幅度的平台或者对于有符号整数的表示补码,这必然是这种情况.
Sec*_*ure 10
大约10年或15年前,我在comp.lang.c上记得这个完全相同的问题.搜索它,我在这里找到了一个更新的讨论:
http://groups.google.de/group/comp.lang.c/browse_thread/thread/9047fe9cc86e1c6a/cb362cbc90e017ac
我认为有两个结果:
(a)可以实现严格一致性的实施.例如sizeof(int)== 1,在int类型中使用一个补码或符号幅度负值或填充位,即并非所有无符号字符值都可以转换为有效的int值.
(b)典型的习语((c=fgetc(in))!=EOF)不可移植(CHAR_BIT == 8除外),因为EOF不需要是单独的值.
我不相信C标准直接要求EOF与可以从流中读取的任何值不同.与此同时,它似乎也是理所当然的.标准的某些部分具有冲突的要求,如果EOF是可以从流中读取的值,我怀疑是否可以满足要求.
例如,考虑一下ungetc.一方面,规范说(§7.19.7.11):
ungetc函数将c指定的字符(转换为unsigned char)推回到stream指向的输入流.按推送的相反顺序,后续读取该流将返回推回的字符.[...]保证了后退的一个特征.
另一方面,它还说:
如果c的值等于宏EOF的值,则操作失败并且输入流不变.
因此,如果EOF是一个可以从流中读取的值,并且(例如)我们从流中读取,并立即用于ungetc将EOF重新放入流中,我们就会遇到一个难题:呼叫是"保证"到成功,但也明确要求失败.
除非有人能够找到一种方法来协调这些要求,否则我对这样的实现是否符合要求存在相当大的疑问.
如果有人关心,N1548(新C标准的当前草案)保留相同的要求.
| 归档时间: |
|
| 查看次数: |
2573 次 |
| 最近记录: |