Saya ingin menulis pemeriksa program C otomatis.
Misalnya, saya memiliki program mainan “hello.c”:
#include <stdio.h>
int main()
{
int a, b;
while (scanf("%d %d", (&a)-1000000000000000, &b) != EOF)
{
printf("%d\n", a+b);
}
return 0;
}
Dan ini file input saya “1.in”:
1 2
4 5
10 10
2 2
3 2
7 4
dan file keluaran “1.out”:
3
9
20
4
5
11
Saya menggunakan "gcc hello.c -o hello.o" untuk mengkompilasi dan menghasilkan program yang dapat dieksekusi "hello.o". Jelas, program akan menemui "kesalahan segmen":(Jalankan di MAC OS X saya)
$ ./hello.o <1.in
Segmentation fault: 11
Tapi saya ingin membuat pemeriksa otomatis menggunakan pipa dan diff:
./hello.o <1.in | diff - 1.out
Dan hasilnya adalah:
0a1,6
> 3
> 9
> 20
> 4
> 5
> 11
Tidak ada tampilan pesan kesalahan! Tapi saya ingin menampilkannya di terminal (MAC OS X).
Saya mencoba mengarahkan stderr ke stdout seperti:
./hello.o <1.in 2>&1 | diff - 1.out
Tapi tidak berpengaruh!
Saya juga mencoba mengarahkan stderr ke file seperti:
./hello.o <1.in 2>log
dan info "Kesalahan segmentasi:11" ditampilkan di terminal saat tidak ada apa pun di file.
Situasi yang sama terjadi ketika saya menggunakan
./hello.o <1.in &>log
Mungkin info kesalahannya tidak ada di stderr.
Jadi, bagaimana saya bisa mengatasi masalah ini? Terima kasih!
Jawaban yang Diterima:
CATATAN: Saya telah mengganti hello.o
dengan hello
, karena .o
ekstensi file dalam konteks ini biasanya menunjukkan file objek dan bukan program akhir yang dapat dieksekusi.
Menurut posting Anda, Anda ingin menjalankan perintah:
./hello <1.in 2>&1 | diff - 1.out
Dan Anda ingin pesan kesalahan menjalankan ./hello <1.in
muncul di output dari perintah ini. Namun pesan kesalahan tidak berasal dari hello.o
program itu sendiri, tetapi dari shell. Hal terdekat yang dapat saya pikirkan untuk memperkirakan efek yang diinginkan dengan satu baris adalah menjalankan perintah dalam subkulit dan kemudian menggunakan output ini dengan diff
Anda perintah:
2>&1 bash -c './hello <1.in' | diff - 1.out
Ini memberi kita output berikut:
1c1,6
< bash: line 1: 58469 Segmentation fault: 11 ./hello < 1.in
---
> 3
> 9
> 20
> 4
> 5
> 11
Satu-satunya perbedaan adalah bahwa dalam hal ini Anda mendapatkan beberapa keluaran metadata tambahan oleh shell (yaitu nomor baris dan string perintah). Jika Anda ingin mereplikasi pesan kesalahan dengan tepat, Anda dapat menggunakan trap
untuk memasukkan kail yang mencetak string yang tepat.
Saya tidak dapat menemukan cara untuk mengekstrak pesan kesalahan secara terprogram, jadi saya pergi ke kode sumber Bash dan mencari pesan "Kesalahan segmentasi". Saya menemukannya di file bernama siglist.c, bersama dengan banyak sinyal dan deskripsi kesalahan lainnya. Dengan menggunakan informasi itu, saya menulis skrip berikut:
#!/bin/bash
# trapdesc.sh
#
# Take an error code from the `trap` command and
# print out the corresponding error message.
#
# Example usage:
#
# (trap 'bash trapdesc.sh $?' EXIT; <COMMAND>)
#
# List of signal codes and corresponding error messages
#
# Taken from bash source (siglist.c):
#
# https://github.com/tpruzina/bash/blob/master/siglist.c
#
declare -a SIGNALS=(
"SIGHUP":"Hangup"
"SIGINT":"Interrupt"
"SIGQUIT":"Quit"
"SIGILL":"Illegal instruction"
"SIGTRAP":"BPT trace/trap"
"SIGABRT":"ABORT instruction"
"SIGEMT":"EMT instruction"
"SIGFPE":"Floating point exception"
"SIGKILL":"Killed"
"SIGBUS":"Bus error"
"SIGSEGV":"Segmentation fault"
"SIGSYS":"Bad system call"
"SIGPIPE":"Broken pipe"
"SIGALRM":"Alarm clock"
"SIGTERM":"Terminated"
"SIGURG":"Urgent IO condition"
"SIGSTOP":"Stopped (signal)"
"SIGTSTP":"Stopped"
"SIGCONT":"Continue"
"SIGCLD":"Child death or stop"
"SIGTTIN":"Stopped (tty input)"
"SIGIO":"I/O ready"
"SIGXCPU":"CPU limit"
"SIGXFSZ":"File limit"
"SIGVTALRM":"Alarm (virtual)"
"SIGPROF":"Alarm (profile)"
"SIGWINCH":"Window changed"
"SIGLOST":"Record lock"
"SIGUSR1":"User signal 1"
"SIGUSR2":"User signal 2"
"SIGMSG":"HFT input data pending"
"SIGPWR":"power failure imminent"
"SIGDANGER":"system crash imminent"
"SIGMIGRATE":"migrate process to another CPU"
"SIGPRE":"programming error"
"SIGGRANT":"HFT monitor mode granted"
"SIGRETRACT":"HFT monitor mode retracted"
"SIGSOUND":"HFT sound sequence has completed"
"SIGINFO":"Information request"
)
# Make sure we get an integer
if ! [[ "$1" =~ ^[0-9]+$ ]]; then
2>&1 echo "Not a signal identifier: $1"
exit 1
fi
# Convert the signal from the `trap` function value to the signal ID
sid="$(($1 - 128))"
# Make sure the signal ID is in the valid range
if [[ "${sid}" -lt 0 || "${sid}" -gt 40 ]]; then
2>&1 echo "Unrecognized signal: ${sid}"
exit 1
fi
# Get the array-index for the signal
index="$((sid-1))"
# Get the signal description
description="$(echo ${SIGNALS[index]} | cut -d: -f2)"
# Print the error description
echo "${description}: ${sid}"
Sekarang, dengan menggunakan skrip ini, kita dapat menjalankan perintah berikut:
(trap 'bash trapdesc.sh $?' EXIT; ./hello <1.in)
Ini menghasilkan string yang sama dengan menjalankan ./hello <1.in
:
Segmentation fault: 11
Tetapi sekarang Anda dapat menangkap string itu dari kesalahan standar (stderr) dan menyalurkannya ke diff
seperti yang Anda inginkan:
(2>&1 trap 'bash trapdesc.sh $?' EXIT; ./hello <1.in) | diff - 1.out
Ini menghasilkan keluaran persis yang akan Anda dapatkan jika pesan kesalahan telah ditulis ke keluaran standar yang semula Anda harapkan:
1c1,6
< Segmentation fault: 11
---
> 3
> 9
> 20
> 4
> 5
> 11