errno值未更新

时间:2012-04-18 14:13:26

标签: c errno

在连续调用套接字函数期间未更新errno值时,问题可能是什么?

socket (AF_INET, -1, 0);
socket (AF_INET, SOCK_STREAM, -1);

第一个应该有errno = EINVAL 第二个应该有errno = EPROTONOSUPPORT


根据@JonathanLeffler提供的代码,cygwin的输出如下:

*$ ./socket.exe
Error from socket(AF_INET, -1, 0): 124 (Socket type not supported)
-- errno = 124 (Socket type not supported)
Error from socket(AF_INET, SOCK_STREAM, -1): 123 (Protocol not supported)
-- errno = 123 (Protocol not supported)
socket(AF_INET, SOCK_STREAM, 0) succeeded (fd = 3)
-- errno = 123 (Protocol not supported)*

编辑下面的代码是为了在创建套接字

之前创建套接字fd0
int fd0 = socket(AF_INET, SOCK_STREAM, 0);
if (fd0 < 0)
    printf("Error from socket(AF_INET, SOCK_STREAM, 0): %d (%s)\n", errno, strerror(errno));
else
{
    printf("socket(AF_INET, SOCK_STREAM, 0) succeeded (fd = %d)\n", fd0);
    close(fd0);
}
printf("-- errno = %d (%s)\n", errno, strerror(errno));

int fd1 = socket(AF_INET, -1, 0);
.....

结果如下:

*$ ./socket.exe
socket(AF_INET, SOCK_STREAM, 0) succeeded (fd = 3)
-- errno = 0 (No error)
Error from socket(AF_INET, -1, 0): 124 (Socket type not supported)
-- errno = 124 (Socket type not supported)
Error from socket(AF_INET, SOCK_STREAM, -1): 123 (Protocol not supported)
-- errno = 123 (Protocol not supported)
socket(AF_INET, SOCK_STREAM, 0) succeeded (fd = 3)
-- errno = 123 (Protocol not supported)*

预计第一个和最后一个套接字创建应具有相同的errno值。


但是如何解释这个输出呢?第5和第6个套接字创建具有相同的errno值,但错误的原因是不同的。

$ ./test_select.exe
[1] ierr = 124, iSocket = -1 socket(AF_INET, -1, 0);
 : Socket type not supported
[2] ierr = 124, iSocket = -1 socket(AF_INET, -1, 0);
 : Socket type not supported
[3] ierr = 124, iSocket = 3 socket(AF_INET, SOCK_STREAM, 0);
 : Socket type not supported
[4] ierr = 124, iSocket = -1 socket (AF_INET, -1, 0);
 : Socket type not supported
[5] ierr = 123, iSocket = -1 socket (AF_INET, SOCK_STREAM, -1);
 : Protocol not supported
[6] ierr = 123, iSocket = -1 socket (AF_INET, -1, 0)
 : Protocol not supported
[7] ierr = 124, iSocket = -1 socket(AF_INET, SOCK_STREAM, -1)
 : Protocol not supported

实际代码如下:

   sockfd = socket(AF_INET, -1, 0);
    err = errno;
    printf("[1] err = %d, sockfd = %d socket(AF_INET, -1, 0);\n", err, sockfd);
    perror(" ");
    sockfd = socket(AF_INET, -1, 0);
     err = errno;
    printf("[2] err = %d, sockfd = %d socket(AF_INET, -1, 0);\n", err, sockfd);
    perror(" ");
     sockfd = socket(AF_INET, SOCK_STREAM, 0);
    err = errno;
    printf("[3] err = %d, sockfd = %d socket(AF_INET, SOCK_STREAM, 0);\n", err, sockfd);
    perror(" ");
    close(sockfd);
    sockfd = socket(AF_INET, -1, 0);
    err = errno;
    printf("[4] err = %d, sockfd = %d socket (AF_INET, -1, 0);\n", err, sockfd);
    perror(" ");
    sockfd = socket(AF_INET, SOCK_STREAM, -1);
    err = errno;
    printf("[5] err = %d, sockfd = %d socket (AF_INET, SOCK_STREAM, -1);\n", err, sockfd);
    perror(" ");
    sockfd = socket(AF_INET, -1, 0);
    err = errno;
    printf("[6] err = %d, sockfd = %d socket (AF_INET, -1, 0)\n", err, sockfd);
    perror(" ");
    err = errno;
    sockfd = socket(AF_INET, SOCK_STREAM, -1);
    printf("[7] err = %d, sockfd = %d socket(AF_INET, SOCK_STREAM, -1)\n", err, sockfd);
    perror(" ");

2 个答案:

答案 0 :(得分:11)

errno永远不会被标准库函数清除,只能设置。此外,任何标准库函数都可以虚假地设置它,否则不会记录该行为。

基本上,使用errno的唯一正确方法是仅在标准库函数返回指示错误的值后立即检查它,并在需要时将其保存在另一个变量中为了以后保留它。

对于select和大多数系统调用,指示错误的返回值为-1,这意味着如果它返回-1,则只应检查errno

答案 1 :(得分:9)

没有库函数将errno设置为零。如果你想让它归零,你的程序必须这样做。

当函数说失败时,您只能有意义地测试errno以获取信息(即使这样,只有当其手册页指示它设置errno时)。您可以通过成功的函数将errno设置为非零。例如,在Solaris上,在写入文件而不是终端时,经常在标准I / O调用后在errno中找到ENOTTY。

在您的示例中,无法保证给定的错误调用函数将设置多个可能的错误值中的哪一个。只要报告一个有效的错误条件,由系统决定它报告的错误。所以,你需要给出一个令人信服的例子,说明为什么第二个调用应该返回EINVAL而不是EBADF;你写的问题没有包含足够的信息让我们认罪。

另请注意,声明errno的唯一安全方法是通过标头:#include <errno.h>。特别是在线程环境中,通常不仅仅是extern int errno;。例如,在Mac OS X上,它可以定义为:

extern int * __error(void);
#define errno (*__error())

也就是说,__error是一个返回指向整数的指针的函数,errno是一个取消引用该指针的宏,成为一个可修改的左值。


代码分析

给定的代码是:

socket (AF_INET, -1, 0);
socket (AF_INET, SOCK_STREAM, -1);

转换为可运行的代码,这可能会变成:

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

int main(void)
{
    int fd1 = socket(AF_INET, -1, 0);
    if (fd1 < 0)
        printf("Error from socket(AF_INET, -1, 0): %d (%s)\n", errno, strerror(errno));
    else
    {
        printf("socket(AF_INET, -1, 0) succeeded (fd = %d)\n", fd1);
        close(fd1);
    }
    printf("-- errno = %d (%s)\n", errno, strerror(errno));

    int fd2 = socket(AF_INET, SOCK_STREAM, -1);
    if (fd2 < 0)
        printf("Error from socket(AF_INET, SOCK_STREAM, -1): %d (%s)\n", errno, strerror(errno));
    else
    {
        printf("socket(AF_INET, SOCK_STREAM, -1) succeeded (fd = %d)\n", fd2);
        close(fd2);
    }
    printf("-- errno = %d (%s)\n", errno, strerror(errno));

    int fd3 = socket(AF_INET, SOCK_STREAM, 0);
    if (fd3 < 0)
        printf("Error from socket(AF_INET, SOCK_STREAM, 0): %d (%s)\n", errno, strerror(errno));
    else
    {
        printf("socket(AF_INET, SOCK_STREAM, 0) succeeded (fd = %d)\n", fd3);
        close(fd3);
    }
    printf("-- errno = %d (%s)\n", errno, strerror(errno));

    return(0);
}

在Mac OS X 10.7.3上运行,这会产生:

Error from socket(AF_INET, -1, 0): 43 (Protocol not supported)
-- errno = 43 (Protocol not supported)
Error from socket(AF_INET, SOCK_STREAM, -1): 43 (Protocol not supported)
-- errno = 43 (Protocol not supported)
socket(AF_INET, SOCK_STREAM, 0) succeeded (fd = 3)
-- errno = 43 (Protocol not supported)

正如我之前所说,返回的错误取决于系统。