【问题标题】:Write returns different error from main than within a function called from main?写从main返回的错误与从main调用的函数中返回的错误不同吗?
【发布时间】:2021-01-27 04:41:39
【问题描述】:

这个问题在标题中听起来很奇怪。我在 MacOSX 的 Assembler 中创建了一个 _ft_write,它会在出现错误时设置 errno。这是我的_ft_write:

extern ___error
global _ft_write

section .text
    _ft_write:
        mov rax, 0x2000004
        clc
        syscall
        jc error
        ret
    
    error:
        push rax
        call ___error
        pop rbx
        mov [rax], ebx
        mov rax, -1
        ret

用我的 ft_write 和 C 的原始写入进行实验,我编写了一个调用 ft_write 并使用相同参数写入的 main,并在出现错误时打印 ERRNO 和相关的错误消息。如果我从 main 调用 ft_write 和 write 并将它们传递一个 NULL 字符串作为第二个参数,则两个版本都返回 ERRNO 14,错误地址。如果我通过将所有相同的参数发送到另一个函数来调用它们,然后调用 ft_write 并在该函数中写入 - 我的 ft_write 继续返回 14,错误地址,如您所料,但 C 的写入返回 22,无效参数!什么? O_O

所以有了这个程序:

int main(void)
{
    int bytes;
    int *string;

    string = NULL;
    printf("Write Res: %d\n", (bytes = ft_write(1, string, 13)));
    if (bytes < 0)
    {
        printf("My Errno: %d\n", errno);
        perror("\0");
    }
    printf("Write Res: %d\n", (bytes = write(1, string, 13)));
    if (bytes < 0)
    {
        printf("C's Errno: %d\n", errno);
        perror("\0");
    }
    return (0);
}

我明白了:

Write Res: -1
My Errno: 14
Bad address
Write Res: -1
C's Errno: 14
Bad address

然而,有了这个程序:

void    testwrite(int fd, char *string, int bytes)
{
    printf("Write Res: %d\n", (bytes = ft_write(fd, string, bytes)));
    if (bytes < 0)
    {
        printf("My Errno: %d\n", errno);
        perror("\0");
    }
    printf("Write Res: %d\n", (bytes = write(fd, string, bytes)));
    if (bytes < 0)
    {
        printf("C's Errno: %d\n", errno);
        perror("\0");
    }
}


int main(void)
{
    testwrite(1, NULL, 13);
    return (0);
}

我明白了:

Write Res: -1
My Errno: 14
Bad address
Write Res: -1
C's Errno: 22
Invalid argument

据我所见,没有任何变化可以解释为什么 C 语言编写应该更改错误消息。有谁知道发生了什么? O_O

【问题讨论】:

  • 这可能不是问题,但要在技术上正确errno 必须在功能失败后立即检查。在这种情况下,printf 是检查 errno 之前的最后一次调用,而不是实际的写入调用。
  • 只有在 printf 失败并设置 errno 时才会出现这种情况,但我知道它不会失败。最终这是一个愚蠢的疏忽......我一直在函数中重用“字节”,即使我在第一次调用后重新分配它是 ft_write 的结果。愚蠢的。 :p 谢谢!
  • 不正确。 errno 仅在最后一个函数调用失败时才有效。如果函数调用成功,则 errno 在技术上是无效的,不应使用。 errno man page:The value in errno is significant only when the return value of the call indicated an error (i.e., -1 from most system calls; -1 or NULL from most library functions); a function that succeeds is allowed to change errno.
  • 我明白了。感谢您的澄清。有很多东西要学!我将在写入之后和 printf 之前存储 errno,以确保它始终正确。
  • 我不确定MacOS调用约定,但据我了解,也不允许修改rbx寄存器。 (修改后必须恢复原值。)

标签: c macos assembly write


【解决方案1】:

您修改bytes(变为-1)以便最后一次调用是

write(fd, ..., -1)'

【讨论】:

  • 呃,谢谢...就是这样。对不起,我是新手,所以我还在犯愚蠢的错误!感谢您指出。
猜你喜欢
  • 1970-01-01
  • 2013-02-17
  • 2015-07-18
  • 2021-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多