3

我正在实现与perror()我正在使用的 API 等效的功能。

perror() ISO C stddoc说:

perror() 函数不应改变标准错误流的方向。

但以编程方式,这意味着什么?

fprintf(stderr, .. )目前正在使用。是误用了吗?如果是真的,为什么?如果我的实现中有一些错误(见下文),请给我点。

根据我的解释查看我的 C 代码:

void
fooapi_perror(const char *s)
{
  char *emsg;

  if(s != NULL && *s != '\0')
    fprintf(stderr, "%s: ", s);

  emsg = fooapi_strerror(GetLastErrorCode()); 
  fprintf(stderr, "%s\n",  emsg); 
  free(emsg);
}
4

2 回答 2

9

每个 C 流都有一个属性——“面向”或“面向宽”或“面向字节”的“方向”,这是由该流上的第一个操作确定的。当流没有“方向”时,您可以更改蒸汽的方向。调用方向与流方向冲突的任何函数会导致未定义的行为。

例如, printf 会使蒸汽变成面向字节的,而 wprintf 会使蒸汽变成面向宽的。

就您的问题而言, perror 不应改变其流的方向。

因此,在您的代码中,如果错误使用的流已经有一个方向,您应该确保您没有调用其方向与流的当前方向冲突的函数。

于 2012-07-14T16:15:38.077 回答
3

您可以使用 确定流的方向fwide(3),并使用它来决定是否调用fprintffwprintf

void
fooapi_perror(const char *s)
{
    const char *emsg = fooapi_strerror(fooapi_geterrcode());

    if (fwide(stderr, 0) <= 0) {
        // byte-oriented or not yet oriented
        if (s && *s)
            fprintf(stderr, "%s: %s\n", s, emsg);
        else
            fprintf(stderr, "%s\n", emsg);
    } else {
        // wide-oriented
        if (s && *s)
            fwprintf(stderr, L"%s: %s\n", s, emsg);
        else
            fwprintf(stderr, L"%s\n", emsg);
    }

    free(emsg);
}

注意:当流尚未获得方向时,这不符合“不改变流方向”的要求,因为没有办法取消流的方向,也没有办法将输出发送到流而不给它一个方向。 在这种情况下,GNU libc 的实现采用perror了一种肮脏的 hack(复制底层文件描述符!)也许我们应该把它归结为“标准 C 宽字符支持无论如何都不适合目的”并继续前进。

Tangential kibitz:fooapi_strerror应该返回一个指向字符串常量的指针,而不是必须为freed 的指针。

于 2012-07-14T17:23:38.423 回答