我正在为练习编写汇编程序。汇编程序使用c库函数。我特别关注fgets()函数。 fgets手册页说明:
fgets() reads in at most one less than size characters from stream and
stores them into the buffer pointed to by s. Reading stops after an
EOF or a newline. If a newline is read, it is stored into the buffer.
A terminating null byte ('\0') is stored after the last character in
the buffer.
我已经声明了一个1024字节的缓冲区,并在fgets功能中使用它来从文件中读取文本。但该程序返回1019个字符。它似乎总是返回5个字符,所以如果我使用1029的缓冲区,它确实会返回1024个字符。我想知道为什么fgets功能以这种方式工作还是我的代码?我的计划如下:
#include <stdio.h>
int main(){
FILE *fopen(), *fp, *fp2;
char buff[1024];
fp = fopen("test.txt", "r");
fgets(buff, 1024, (FILE*)fp);
fp2 = fopen("outputtest.txt", "w");
//fprintf(fp2, "This is testing for fprintf...\n");
fputs(buff, fp2);
fclose(fp);
fclose(fp2);
}
输入在1020位置不包含任何空字节或换行符,因此最多应返回1023。以下是输入:
这是一个测试文件。 Linux的发展是其中之一 自由和开源软件协作的突出例子。该 底层源代码可以使用,修改和 根据条款由任何人分发商业或非商业 其各自的许可证,例如GNU通用公共许可证。 通常,Linux以称为Linux发行版的形式打包, 用于桌面和服务器。一些流行的主流Linux 发行版是Debian,Ubuntu,Linux Mint,Fedora,openSUSE,Arch Linux和Gentoo,以及商业红帽企业Linux 和SUSE Linux Enterprise Server发行版。 Linux发行版 包括Linux内核,支持实用程序和库,以及 通常需要大量的应用软件来实现 分发的预期用途。面向桌面使用的发行版 通常包括X11,Wayland实现或Mir作为 窗口系统,以及附带的桌面环境 GNOME或KDE软件编译;一些发行版也可能 包括资源较少的桌面,如LXDE或Xfce。 打算在服务器上运行的发行版可能会省略所有图形 标准安装的环境,而不是包括其他环境 用于设置和操作LAMP等解决方案堆栈的软件。因为 Linux可以自由再发行,任何人都可以为其创建发行版 任何用途。
输出如下:
这是一个测试文件。 Linux的发展是其中之一 自由和开源软件协作的突出例子。该 底层源代码可以使用,修改和 根据条款由任何人分发商业或非商业 其各自的许可证,例如GNU通用公共许可证。 通常,Linux以称为Linux发行版的形式打包, 用于桌面和服务器。一些流行的主流Linux 发行版是Debian,Ubuntu,Linux Mint,Fedora,openSUSE,Arch Linux和Gentoo,以及商业红帽企业Linux 和SUSE Linux Enterprise Server发行版。 Linux发行版 包括Linux内核,支持实用程序和库,以及 通常需要大量的应用软件来实现 分发的预期用途。面向桌面使用的发行版 通常包括X11,Wayland实现或Mir作为 窗口系统,以及附带的桌面环境 GNOME或KDE软件
以上以一个空格结束,组成完整的1019个字符返回。我想知道造成这种情况的原因。我的汇编程序有效但当然读取的字符数量不正确。有人可以向我解释为什么会这样吗?
提前致谢。
答案 0 :(得分:2)
我相信其他评论者已经明白了。两个Unicode破折号各有1个字符,但有3个字节。这使你比字符多4个字节。我相信第5个丢失字节是为空终结符腾出空间的一个字符。
我之前的评论询问是否有隐藏的BOM(再见订单标记)已关闭。它似乎是可见的嵌入式Unicode短划线字符,而不是隐藏的嵌入式Unicode BOM。
答案 1 :(得分:2)
将评论转移到答案中。
在Mac OS X上运行,您的代码根据ls -l
生成1023字节的输出文件。但是我的输出文件在'KDE软件'(带有空格)之后结束。你是如何在输出上建立文件大小的?你对自己的数量有多确定?问题是否出现在较短的缓冲区大小(比如说32个字节)中 - 也就是说,输出的输出是否比您想象的要短5个字节?
示例文本包含两个U + 2014 EM DASH( - )实例,其UTF-8编码为e2 80 94,这当然是相关的。
这很有可能 - 到了确定的程度。它解释了为什么vim
在我使用1024|
时似乎错误放置了光标 - 它计算字符而不是字节 - 这让我感到困惑。当我在Mac上运行:wc -m
时,我得到1019个(多字节)字符,但仍然是1023个字节。
我使用atom.io文本编辑器来获取计数,错误开始发生在256字节。我尝试了128个字节,64个字节,32个字节,并且没有发生错误,它分别返回127个字节,63个字节,31个字节(如手册页所述“最多只有一个小于字符串的大小字符”)。
由于第一个' - 'em-dash出现在偏移量194处,看起来您的问题与“字节与字符”完全相关,而且您使用的是UTF-8编码数据。作为非零(NUL)字节的纯流处理,您可以将最多1023个字节读入buff,这就是您的代码正在执行的操作。但是,如果计算字符而不是字节,则有两个3字节字符(两个em-dash字符),这意味着字符数比字节数少4。你刚刚知道你的编辑会计算角色;诸如ls
之类的程序报告字节。这两个数字通常是不同的。
我们还可以观察到引用的手册页引用的'字符'是char
- 类型字符,又称'字节'(在大多数系统上 - 有char
不是8的机器位字节)。这种混淆部分源于C标准。
ISO / IEC 9899:2011§7.21.7.2 fgets
函数说:
fgets
函数最多读取的数字少于n
指定的字符数 从stream
指向的流进入s
指向的数组。没有额外的 在换行符(保留)或文件结束后读取字符。一个 在读入数组的最后一个字符后立即写入空字符。
斜体强调添加
相比之下,fgets()
的POSIX规范表明fgets()
是根据 bytes 指定的:
fgets()
函数应将 bytes 从stream
读入s
指向的数组,直到读取n-1
个字节,或者读取<newline>
并将其传输到s
,否则会遇到文件结束条件。然后该字符串以空字节终止。
斜体强调添加
该页面注释为:
此参考页面上描述的功能与ISO C标准一致。此处描述的要求与ISO C标准之间的任何冲突都是无意的。本卷POSIX.1-2008符合ISO C标准。
这是引用ISO / IEC 9899:1999,因为POSIX.1-2008是在C11之前发布的,但C99§7.19.7.2中的措辞与C11中的相同。可以说,POSIX措辞比C标准措辞更容易理解。但是,标准的定义部分说:
3.7
1 字符
用于组织,控制或的一组元素的成员 数据表示 3.7.1 1 字符 单字节字符
适合字节的位表示 3.7.2
1 多字节字符 表示扩展字符集成员的一个或多个字节的序列 源或执行环境
2注意扩展字符集是基本字符集的超集。3.7.3
1 宽字符 值可由wchar_t
类型的对象表示,能够表示任何字符 在当前的区域设置
因此,在上下文中,“字符”表示大多数人认为的“字节”(有警告 - 并非所有机器都有CHAR_BIT == 8
)。