如何从 stderr 读取错误消息?
How can I read the error message from stderr?
我们正在研究 Pipes,我必须创建一个 C 代码来读取编译另一个 C 程序的错误消息。我正在使用 dup2 将 stederr
复制到管道的写入端,之后我使用 read
方法从管道的另一端读取,但在某些情况下我无法读取整个错误信息。
这是我正在尝试做的事情:
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
const char *const cmd0 = argv[1];
int fds_pair[2];
pipe(fds_pair);
pid_t pid;
if ((pid = fork()) == 0) {
close(fds_pair[0]);
/// stderr <- pipe's write
dup2(fds_pair[1], 2);
execlp("g++", "g++", cmd0, "-o", "my_program", NULL);
return 0;
} else {
close(fds_pair[1]);
char expression[256];
memset(expression, '[=10=]', sizeof(expression));
size_t readret;
readret = read(fds_pair[0], &expression, sizeof(expression));
printf("%s", expression);
while (readret > 0) {
readret = read(fds_pair[0], expression, sizeof(expression));
printf("%s", expression);
}
}
close(fds_pair[0]);
return 0;
}
我面临的问题是,当我尝试获取程序错误时:
1 #include <stdio.h>
2
3 int main () {
4 ;float v_05778c89;
5 float v_ char v_ int v_ double v_ double v_
6 }
这是我从上面的代码中读到的错误消息:
main2.c: In function ‘int main()’:
main2.c:5:5: error: expected initializer before ‘float’
5 | float v_
| ^~~~~
我没有收到错误:expected '=', ',', ';', 'asm' or 'attribute' before ' }' 令牌
6 | }
我对自己做错了什么或必须解决的问题感到困惑
您期望的错误消息 (expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘attribute’ before ‘}’ token 6 | }
) 是典型的 MS Visual C++,而不是 GNU g++
。这可能是主要问题——不切实际的期望。
我修改了您的代码以包含我的版本中的第一段代码,如下所示,以便使用 argc
并通过我的默认编译选项。
当我运行你修改后的代码(源文件re23.c
编译成re23
),我得到输出:
$ re23 main2.c
main2.c: In function ‘int main()’:
main2.c:5:12: error: expected initializer before ‘char’
5 | float v_ char v_ int v_ double v_ double v_
| ^~~~
main2.c: In function ‘int main()’:
main2.c:5:12: error: expected initializer before ‘char’
5 | float v_ char v_ int v_ double v_ double v_
| ^~~~
$
该消息出现两次,因为您没有正确处理来自子进程(C++ 编译器)的 I/O。基本上,您需要在打印任何内容之前读取数据并检查它是否有效。
编译(GCC 11.2.0 运行ning on macOS Big Sur 11.6.4):
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -fno-common re23.c -o re23
$
我也在评论中提到了各种问题。我相信它们都已固定在下面的代码中,根据我的标准可以正常工作。它与您的相似,并且与您的相似,但有一些关键差异。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s sourcefile.cpp\n", argv[0]);
exit(EXIT_FAILURE);
}
const char *const cmd0 = argv[1];
int fds_pair[2];
if (pipe(fds_pair) < 0)
{
fprintf(stderr, "%s: failed to create pipe: %d %s\n",
argv[0], errno, strerror(errno));
exit(EXIT_FAILURE);
}
pid_t pid = fork();
if (pid < 0)
{
fprintf(stderr, "%s: failed to fork: %d %s\n",
argv[0], errno, strerror(errno));
exit(EXIT_FAILURE);
}
else if (pid == 0)
{
dup2(fds_pair[1], STDERR_FILENO);
close(fds_pair[0]);
close(fds_pair[1]);
execlp("g++", "g++", cmd0, "-o", "my_program", NULL);
fprintf(stderr, "%s: failed to exec '%s': %d %s\n",
argv[0], "g++", errno, strerror(errno));
exit(EXIT_FAILURE);
}
else
{
close(fds_pair[1]);
char expression[256];
ssize_t readret;
while ((readret = read(fds_pair[0], &expression, sizeof(expression))) > 0)
{
printf("%.*s", (int)readret, expression);
}
close(fds_pair[0]);
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("%s: child %d exited with status 0x%.4X\n", argv[0], corpse, status);
}
return 0;
}
这里有一些示例 运行s — 我使用源代码 re37.c
作为上面的源代码,创建程序 re37
:
$ ./re37
Usage: ./re37 sourcefile.cpp
$ ./re37 nonexistent.cpp
cc1plus: fatal error: nonexistent.cpp: No such file or directory
compilation terminated.
./re37: child 4644 exited with status 0x0100
$ cat main2.c
#include <stdio.h>
int main () {
;float v_05778c89;
float v_ char v_ int v_ double v_ double v_
}
$ ./re37 main2.c
main2.c: In function ‘int main()’:
main2.c:5:12: error: expected initializer before ‘char’
5 | float v_ char v_ int v_ double v_ double v_
| ^~~~
./re37: child 4670 exited with status 0x0100
$
我们正在研究 Pipes,我必须创建一个 C 代码来读取编译另一个 C 程序的错误消息。我正在使用 dup2 将 stederr
复制到管道的写入端,之后我使用 read
方法从管道的另一端读取,但在某些情况下我无法读取整个错误信息。
这是我正在尝试做的事情:
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
const char *const cmd0 = argv[1];
int fds_pair[2];
pipe(fds_pair);
pid_t pid;
if ((pid = fork()) == 0) {
close(fds_pair[0]);
/// stderr <- pipe's write
dup2(fds_pair[1], 2);
execlp("g++", "g++", cmd0, "-o", "my_program", NULL);
return 0;
} else {
close(fds_pair[1]);
char expression[256];
memset(expression, '[=10=]', sizeof(expression));
size_t readret;
readret = read(fds_pair[0], &expression, sizeof(expression));
printf("%s", expression);
while (readret > 0) {
readret = read(fds_pair[0], expression, sizeof(expression));
printf("%s", expression);
}
}
close(fds_pair[0]);
return 0;
}
我面临的问题是,当我尝试获取程序错误时:
1 #include <stdio.h>
2
3 int main () {
4 ;float v_05778c89;
5 float v_ char v_ int v_ double v_ double v_
6 }
这是我从上面的代码中读到的错误消息:
main2.c: In function ‘int main()’:
main2.c:5:5: error: expected initializer before ‘float’
5 | float v_
| ^~~~~
我没有收到错误:expected '=', ',', ';', 'asm' or 'attribute' before ' }' 令牌 6 | }
我对自己做错了什么或必须解决的问题感到困惑
您期望的错误消息 (expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘attribute’ before ‘}’ token 6 | }
) 是典型的 MS Visual C++,而不是 GNU g++
。这可能是主要问题——不切实际的期望。
我修改了您的代码以包含我的版本中的第一段代码,如下所示,以便使用 argc
并通过我的默认编译选项。
当我运行你修改后的代码(源文件re23.c
编译成re23
),我得到输出:
$ re23 main2.c
main2.c: In function ‘int main()’:
main2.c:5:12: error: expected initializer before ‘char’
5 | float v_ char v_ int v_ double v_ double v_
| ^~~~
main2.c: In function ‘int main()’:
main2.c:5:12: error: expected initializer before ‘char’
5 | float v_ char v_ int v_ double v_ double v_
| ^~~~
$
该消息出现两次,因为您没有正确处理来自子进程(C++ 编译器)的 I/O。基本上,您需要在打印任何内容之前读取数据并检查它是否有效。
编译(GCC 11.2.0 运行ning on macOS Big Sur 11.6.4):
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -fno-common re23.c -o re23
$
我也在评论中提到了各种问题。我相信它们都已固定在下面的代码中,根据我的标准可以正常工作。它与您的相似,并且与您的相似,但有一些关键差异。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s sourcefile.cpp\n", argv[0]);
exit(EXIT_FAILURE);
}
const char *const cmd0 = argv[1];
int fds_pair[2];
if (pipe(fds_pair) < 0)
{
fprintf(stderr, "%s: failed to create pipe: %d %s\n",
argv[0], errno, strerror(errno));
exit(EXIT_FAILURE);
}
pid_t pid = fork();
if (pid < 0)
{
fprintf(stderr, "%s: failed to fork: %d %s\n",
argv[0], errno, strerror(errno));
exit(EXIT_FAILURE);
}
else if (pid == 0)
{
dup2(fds_pair[1], STDERR_FILENO);
close(fds_pair[0]);
close(fds_pair[1]);
execlp("g++", "g++", cmd0, "-o", "my_program", NULL);
fprintf(stderr, "%s: failed to exec '%s': %d %s\n",
argv[0], "g++", errno, strerror(errno));
exit(EXIT_FAILURE);
}
else
{
close(fds_pair[1]);
char expression[256];
ssize_t readret;
while ((readret = read(fds_pair[0], &expression, sizeof(expression))) > 0)
{
printf("%.*s", (int)readret, expression);
}
close(fds_pair[0]);
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("%s: child %d exited with status 0x%.4X\n", argv[0], corpse, status);
}
return 0;
}
这里有一些示例 运行s — 我使用源代码 re37.c
作为上面的源代码,创建程序 re37
:
$ ./re37
Usage: ./re37 sourcefile.cpp
$ ./re37 nonexistent.cpp
cc1plus: fatal error: nonexistent.cpp: No such file or directory
compilation terminated.
./re37: child 4644 exited with status 0x0100
$ cat main2.c
#include <stdio.h>
int main () {
;float v_05778c89;
float v_ char v_ int v_ double v_ double v_
}
$ ./re37 main2.c
main2.c: In function ‘int main()’:
main2.c:5:12: error: expected initializer before ‘char’
5 | float v_ char v_ int v_ double v_ double v_
| ^~~~
./re37: child 4670 exited with status 0x0100
$