1

我有以下代码:

#include <stdio.h>
#include <unistd.h>

int main () {

    int fd = open("filename.dat", O_CREAT|O_WRONLY|O_TRUNC, 0600);
    int result = write(fd, "abcdefghijklmnopqrstuvxz", 100);
    printf("\n\nfd = %d, result = %d, errno = %d", fd, result, errno);
    close(fd);
    return 0;
}

我试图了解当我尝试向文件写入比可用字节多的字节时会发生什么。所以我打电话write并要求程序写入 100 个字节,而我的字节数要少得多。结果:一堆东西stdoutfilename.dat. 如果不是100我使用strlen("abcdefghijklmnopqrstuvxz"),我会得到想要的结果。那么我的问题是:为什么程序试图写超出'\0'我字符串上的字符?这里有一些未定义的行为吗?

4

5 回答 5

4

那么我的问题是:为什么程序试图在我的字符串上写入 '\0' 字符之外的内容?

该函数write(2)不关心 0 终止符。它实际上根本不关心缓冲区内容:它会尝试写入你告诉它的尽可能多的字节。

这里是否发生了一些未定义的行为

当然,试图写的比你写的更多可能会招致操作系统的愤怒,如果它触及不可访问的内存,操作系统可能会决定终止你的进程。

于 2012-09-02T13:49:01.507 回答
1

您使用的write()功能不关心内容。它只是写没有。您告诉它写入文件的字节数。

所以当你说它写 100 个字节并提供少于 100 个字节时。剩余的字节被当作垃圾值。

但是当您使用 时strlen("abcdefghijklmnopqrstuvxz"),您要求write()写入等于字符串长度的字节。所以它在那里工作得很好

于 2012-09-02T13:52:53.823 回答
1

因为有两种技术可以表示一个字符串。有一个以空值结尾的版本,当您定义它的大小和指向第一个字节的指针时,还有另一个版本。写使用第二个。它需要一个数据开始的指针和一个长度来知道应该将多少数据复制到文件中,但它看不到空值。有时这些方法包装了一个简单的 memcpy。

因此,当您定义 100 长度时,在abcdefghijklmnopqrstuvxz程序存储您的“一堆标准输出内容”之后的内存中。这就是你看到垃圾的原因。您很幸运,因为在这些情况下您可以轻松获得 SEGFAULT!

于 2012-09-02T13:53:40.977 回答
0

My question then is: why is the program trying to write beyond a \0因为你希望它写 100 个字符。

Is there some undefined behavior going on here?如果将 100 增加到一个很大的数字,并且该区域位于非特权区域,则这是未定义的行为。

于 2012-09-02T13:52:07.370 回答
0

我认为这里的基本问题是您将 C 字符串视为值,您认为您正在将此值传递给 write 函数,而 write 函数正在写出您的值和额外的垃圾。

C比那个级别低。在 C 中,我们并没有真正传递字符串,而是传递指向字符串的指针,这些字符串是 'char *' 值,但附加了一个承诺,即它们指向应该被视为以空字符结尾的字符串的有效内存块.

write() 函数不关心以 null 结尾的字符串约定。write 调用中的参数提供文件描述符、char * 和缓冲区长度。

此外,编译器将字符串常量转换为 const char 数组。与此等价的情况发生在顶层:

const char *stringconst00001[27] = { 'a', 'b', 'c', ... 'y', 'z', '\0' }

它在 main() 中执行此操作:

int result = write(fd, stringconst00001, 100);
于 2012-09-02T15:28:53.953 回答