语义上相同的代码给出不同的结果

时间:2019-01-16 13:25:33

标签: c io

我无法绕过这个话题,希望标题不要太让人误解。在两个代码段中,write的第三个参数count为何表现不同?似乎调用函数而不是在write中指定数字是一件坏事,但这似乎没什么大不了的。

版本错误:

   int main(int argc, char const *argv[])
{

    char    format[50];         
    char    formattedTime[50];  
    time_t      t;              



    if (read(STDIN_FILENO, format, 50) < 0)
        fatalError("read() error");



    time(&t);   

    strftime(formattedTime, 50, format, localtime(&t));


    if (write(STDOUT_FILENO, formattedTime, strlen(formattedTime) + 1) != strlen(formattedTime) + 1)
        fatalError("write() error");



    return 0;
}

正确的版本:

   int main(int argc, char const *argv[])
{

    char    format[50];         //zeljeni format
    char    formattedTime[50];  //formatirano vreme
    time_t      t;              // trenutno vreme

    // citamo s ulaza zeljeni format vremena

    if (read(STDIN_FILENO, format, 50) < 0)
        fatalError("read() error");


    // zapisujemo trenutno vreme
    time(&t);   

    strftime(formattedTime, 50, format, localtime(&t));

    int n;
    n = strlen(formattedTime) + 1;

    // ispisujemo na izlaz
    if (write(STDOUT_FILENO, formattedTime, n) != n)
        fatalError("write() error");



    return 0;
}

右输出:

%a %b %d
Wed Jan 16

错误的输出:

%a %b %d
Wed Jan 16
0

为什么在调用n的前一步就计算write会带来不同?

编辑: 希望这能满足所有信息。每次都乱七八糟,但要点仍然存在。

2 个答案:

答案 0 :(得分:3)

如果您确实有这种行为,则可能意味着 formattedTime 中缺少空字符,并且偶然地 n 在堆栈中,并通过其引入了空字符存在,或由于存储在堆栈中的数据而造成的等效结果

答案 1 :(得分:1)

read函数主要用于读取二进制数据,而不是字符串。这样,它仅读取您输入的字符(即字符序列,后跟换行符),而不会添加空终止字节。结果,您没有正确格式化的字符串,因此使用strftime可以读取写入未初始化的字节中的内容,也可以读取数组末尾的内容。这将调用undefined behavior

“正确的版本”似乎有效,因为您很幸运。这是未定义行为表现出来的方式之一。其他人可能会看到与您看到的结果相反的结果。

您需要捕获已读取的字节数并手动向该数组添加一个终止的空字节:

int rval;

if ((rval=read(STDIN_FILENO, format, 49)) < 0)
    fatalError("read() error");

 format[rval] = 0;