GNU/Linux >> Belajar Linux >  >> Linux

Bagaimana Cara Mengarahkan Info Kesalahan Program C yang Dapat Dieksekusi ke Stdout? (mac Os X)?

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

Linux
  1. Cara Mengarahkan Output ke File dan Stdout di Linux

  2. Ssh – Redirect Stdout Melalui Ssh?

  3. Bagaimana Membuat Program Dapat Dieksekusi Dari Mana Saja?

  1. Cara mengarahkan output ke file dan stdout

  2. Bagaimana cara mendapatkan alamat MAC mesin Anda menggunakan program C?

  3. Bagaimana Anda keluar dari program X11 tanpa Kesalahan

  1. Bagaimana Cara Mengirim Stdout Ke Beberapa Perintah?

  2. Cara mengarahkan output program sebagai inputnya

  3. Bagaimana cara mengatur file sebagai TIDAK dapat dieksekusi?