-4

我正在尝试显示一个缓冲区,但它以特殊字符显示。这是我的代码:

size_t write(int fd, const void *buf, size_t count)
{

    static size_t (*write_func)(int, const void *, size_t) = NULL;
    if (!write_func)
        write_func = (size_t(*)(int, const void *, size_t)) dlsym(RTLD_NEXT, "write");


    char tmp[count];  

    memcpy(tmp,buf,count);
    printf("  %c \n",tmp[1]);

您对如何解决此问题有任何想法吗?太感谢了!

4

1 回答 1

0

您在堆栈上分配只读数据的副本。这是危险的,因为堆栈空间可能是有限的。(在 Linux 中,只有原始堆栈会动态增长;线程堆栈的大小是固定的,而且通常非常小。)

然后您使用 stdio.hprintf()函数将指定数据的第二个字节(即使count可能是 1)输出到标准输出,因此您很可能访问临时数组之外的内容。

大多数printf()实现write()在内部调用以刷新缓冲区。根据链接的不同,这最终可能是递归的(你的函数调用printf调用你的函数调用printf等等),用尽进程可用的所有 RAM,然后崩溃。

以上没有任何意义。

首先,如果您需要复制输入数据,请使用malloc()and动态复制memcpy(),然后再复制free()。这样你就不会突然开始在多线程程序中导致崩溃(除了 Linux 中的原始进程,堆栈空间是有限且固定的)。

其次,您需要使用write_func通过链接器获得的原始文件。

第三,您需要保留errno以避免在客户端程序中出现不可预见的问题。只需使用临时本地int来存储它。请记住,不仅write(),而且可能修改,malloc()并且您必须对调用者隐藏这些更改。free()errno

第四,返回类型write()is ssize_t, not size_t。前者是签名的,后者可能是未签名的。

第五,总是允许短写。您永远不能依赖获得“完整”块;应用程序进行内部处理,尤其是在使用套接字时,以奇数大小刷新它(特别是 TCP/IP 和 UDP/IP 的 MTU 的倍数)。您对输入/输出的“修改”必须是无状态的。更糟糕的是,如果您的修改更改了缓冲区长度,并且描述符是非阻塞的,并且write_func()调用在修改部分的中间返回一个简短的写入,它没有明智地映射到任何原始字节,你将如何处理它?你不能重试,真的,因为描述符是非阻塞的;原始应用程序可能会挂起——例如,如果以协同处理方式使用,同时从具有严格排序要求的对等进程发送和接收数据——因为当应用程序逻辑级别不允许添加时,您的添加将重新发出写入。

简而言之,您的计划行不通。您可能会让它与一些特定的简单应用程序一起工作,但它可能会严重破坏其他应用程序。无论你想达到什么目标,都有更好的方法。

我希望我不会太直率,但我强烈建议您先了解低级 POSIX I/O 的来龙去脉,然后再围绕它们创建包装器。Linux 手册页项目是我可以推荐的一个很好的参考,但我认为您可能需要先从一些教程开始。

于 2012-07-04T20:56:46.043 回答