# Error handling

## What is Error handling?

&#x20;    Error handing คือ การจัดการข้อผิดพลาด ซึ่งเป็นความผิดพลาดที่โดยทั่วไปแล้วไม่สามารถจัดการภายในโปรแกรม เมื่อเกิด Error ขึ้นอาจส่งผลให้การทำงานของโปรแกรมล้มเหลว เช่น หน่วยความจำไม่พอ เวอร์ชันการทำงานของ library ไม่ถูกรองรับ การเปิดไฟล์ที่ไม่มีอยู่จริง เป็นต้น จึงต้องมีการเขียน Error handling เพื่อแสดงสาเหตุของข้อผิดพลาดนั้นและทำให้โปรแกรมสามารถทำงานต่อไปได้

## **Different methods of Error handling**

&#x20;    การเขียนโปรแกรมภาษา C ไม่ได้มีการสนับสนุนการจัดการข้อผิดพลาด (Error handling) โดยตรง ผู้ออกแบบโปรแกรมต้องทำการเขียนขึ้นมาเอง โดยการใช้คำสั่ง return ส่งคืนค่า -1 หรือ NULL ในกรณีที่เกิดข้อผิดพลาด และสามารถเขียน Error handling ด้วยการใช้ 'คำสั่ง if' ดังตัวอย่าง การหารด้วย 0 (Divide by Zero Errors) ดังต่อไปนี้

{% hint style="info" %}
&#x20;    สำหรับภาษา C++ จะมีตัวสนับสนุนการจัดการข้อผิดพลาด เรียกว่า Exceptions handling ถึงแม้ว่าจะมีตัวสนับสนุนจัดการข้อผิดพลาด แต่ก็สามารถเขียน Error handling ได้เหมือนภาษา c&#x20;
{% endhint %}

{% tabs %}
{% tab title="Example code C" %}

```c
// err_p1_1.c
#include <stdio.h> 

int solution(int a,int b)
{
    if (b > 0) { 
    
        return a / b; 
    } 

    return -1;
}   

int main() {
    printf("%d\n",solution(102,0));
    printf("%d\n",solution(955,5));
    printf("%d\n",solution(1650,2));     
    return 0;
}
```

{% endtab %}

{% tab title="Example code C++" %}

```cpp
// err_p1_2.cpp
#include <iostream>
using namespace std;

int myFunction(int a,int b) {
    if (b == 0) {
	    return -1;
    }    

    return a/b;
}

int main() {
  cout << myFunction(102,0) << endl;
  cout << myFunction(955,5) << endl;
  cout << myFunction(1650,2) << endl;
  return 0;
} 
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="Output" %}

```
-1
191
825
```

{% endtab %}
{% endtabs %}

&#x20;    อย่างที่รู้กันว่าโปรแกรมคอมพิวเตอร์จะไม่สามารถคำนวณค่าที่เกิดจากการหารด้วย 0 เนื่องจากจะส่งผลให้เกิดข้อผิดพลาดในการทำงานและไม่สามารถทำงานต่อไปได้ แต่จากตัวอย่างจะเห็นได้ว่าโปรแกรมสามารถทำงานต่อไปได้ด้วยการเขียน Error handling return ค่า -1&#x20;

&#x20;    ข้อเสียของการส่งค่า return คือ จะทำให้คนอื่นนอกจากผู้ออกแบบโปรแกรมไม่ทราบว่าค่า -1 ที่ถูก return กลับมานั้นเกิดจากสาเหตุอะไร จึงได้มี**การตั้งค่ารหัสตัวแปรส่วนกลาง (Global Variable)** เพื่อระบุว่ารหัสตัวแปรที่ปรากฏเกิดจากสาเหตุอะไร ซึ่งสามารถค้นหารหัสตัวแปรข้อผิดพลาดต่าง ๆ ที่กำหนดไว้จาก <**errno.h**> ที่เป็น header file เรียกวิธีนี้ว่า **Global Variable errno**

### **Global Variable errno**

&#x20;     Global Variable errno ถูกตั้งค่าเป็นตัวแปรส่วนกลางและระบุว่ามีข้อผิดพลาดอะไรที่เกิดขึ้นระหว่างการเรียกใช้ฟังก์ชันใด ๆ ซึ่งสามารถค้นหารหัสตัวแปรข้อผิดพลาดที่กำหนดไว้จาก \<errno.h> **(ภาษา** **C++ สามารถเรียกใช้ได้ทั้งแบบ \<errno.h> และแบบ \<cerrno>)** ดังนั้นโปรแกรมเมอร์สามารถตรวจสอบค่าที่ส่งคืนและสามารถดำเนินการที่เหมาะสมโดยขึ้นอยู่กับค่าที่ส่งคืน ดังตารางต่อไปนี้

![](https://1856353139-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MClo3nC-1US0rbK8Qau%2F-MTAnqtxcWefPDMMif5m%2F-MTAxYa9U0ek93CizeGI%2FScreenshot%20from%202021-02-10%2019-41-15.png?alt=media\&token=0e9fd334-dc19-465d-87ea-4bf928558e48)

{% hint style="warning" %}
errno value จะไม่มีเลข 0 เนื่องจากเลข 0 หมายถึงไม่มีข้อผิดพลาดในโปรแกรม
{% endhint %}

{% tabs %}
{% tab title="Example code C" %}

```c
// err_p1_3.c
#include <stdio.h> 
#include <errno.h> 
  
int main() 
{ 
    // If a file is opened which does not exist, 
    // then it will be an error and corresponding 
    // errno value will be set 
    FILE * fp; 
  
    // opening a file which does 
    // not exist. 
    fp = fopen("text.txt", "r"); 
  
    printf(" Value of errno: %d\n ", errno); 
  
    return 0; 
} 
```

{% endtab %}

{% tab title="Example code C++" %}

```cpp
// err_p1_4.cpp
#include <iostream>
#include <cerrno>
using namespace std;

int main()
{
    cout << "Attempting file access..." << endl;
    FILE *f = fopen("text.txt","r");
    if (f == NULL)   
    {       
        cout << "Something went wrong! errno : " << errno << endl;
    }
    return 0;
}
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="Output" %}

```
Value of errno: 2
```

{% endtab %}
{% endtabs %}

&#x20;    จากตัวอย่างจะเห็นว่าค่าตัวแปร errno ที่ถูกส่งออกมา คือ 2 หมายความว่า โปรแกรมไม่สามารถเปิดไฟล์ที่ต้องการ เนื่องจากไม่มีไฟล์หรือไดเร็กทอรีดังกล่าว

&#x20;   ข้อเสียของการให้ส่งค่าตัวแปรแสดงข้อผิดพลาดเพียงอย่างเดียว คือจะทำให้เกิดความยุ่งยากในการหาคำอธิบายข้อผิดพลาด ดังนั้นจึงได้มีฟังก์ชัน perror() และ strerror() เข้ามาช่วยในการแสดงข้อผิดพลาด

{% hint style="success" %}
**คำถาม** คำสั่ง FILE \*fp และ fopen คืออะไร

**คำตอบ** เป็นรูปแบบการประกาศแฟ้มข้อมูลและเปิดแฟ้มข้อมูล

ข้อมูลอ่านเพิ่มเติม :: [**พื้นฐานการทำงานของไฟล์** ](http://c-by-step.weebly.com/3614363936573609360036343609358536343619360736353591363436093585363336103652361536213660.html)
{% endhint %}

### perror() and strerror()

* &#x20;perror() ย่อมาจาก print error เป็นฟังก์ชันที่ใช้ในการแสดงข้อความของค่า errno ปัจจุบัน โดยที่สามารถแสดงข้อความที่กำหนดไว้ ก่อนการแสดงข้อผิดพลาด

{% tabs %}
{% tab title="Syntax" %}

```cpp
void perror (char*msg);
  msg คือ ข้อความแบบกำหนดเองก่อนการแสดงข้อผิดพลาด
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="Example code C" %}

```c
// err_p1_5.c
// C program to illustrate the 
// use of perror() 
#include <errno.h> 
#include <stdio.h> 
#include <stdlib.h> 
  
// Driver Code 
int main() 
{ 
    FILE* fp; 
  
    // Now try to open same file 
    fp = fopen("file.txt", "r"); 
  
    if (fp == NULL) { 
  
        perror("Error: "); 
        return (-1); 
    } 
  
    // Close the file pointer 
    fclose(fp); 
  
    return (0); 
}
```

{% endtab %}

{% tab title="Example code C++" %}

```cpp
// err_p1_6.cpp
// C++ program to illustrate the 
// use of perror() 
#include <iostream>
#include <errno.h> 
  
// Driver Code 
int main() 
{ 
    FILE* fp; 

    fp = fopen("file.txt", "r"); 
  
    if (fp == NULL) { 
  
        perror("Error: "); 
        return (-1); 
    } 
  
    // Close the file pointer 
    fclose(fp); 
  
    return (0); 
}
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="output" %}

```cpp
Error: : No such file or directory
```

{% endtab %}
{% endtabs %}

* strerror() คือ ฟังก์ชันที่ใช้รับค่าตัวแปรของ errno เพื่อ return ข้อมูลประเภท string มาแสดงผลข้อผิดพลาด

{% tabs %}
{% tab title="Example code C" %}

```c
// err_p1_7.c
// C program to illustrate the 
// use of strerror() 
#include <errno.h> 
#include <stdio.h> 
#include <string.h> 
  
// Driver Code 
int main() 
{ 
    FILE* fp; 
  
    fp = fopen("file.txt", "r"); 
  
    if (fp == NULL) { 
  
        printf("Value of errno: %d\n ", errno); 
        printf("The error message is : %s\n",strerror(errno)); 
        return (-1); 
    } 
  
    // Close the file pointer 
    fclose(fp); 
  
    return (0); 
}

```

{% endtab %}

{% tab title="Example code C++" %}

```cpp
// err_p1_8.cpp
// C++ program to illustrate the 
// use of strerror() 
#include <iostream>
#include <cerrno>
#include <string.h>
using namespace std; 
  
// Driver Code 
int main() 
{ 
    FILE* fp; 
  
    // Now try to open same file 
    fp = fopen("file.txt", "r"); 
  
    if (fp == NULL) { 
  
        cout <<"Value of errno: " << errno << endl; 
        cout << "The error message is : " << strerror(errno) << endl;
        return (-1); 
    } 
  
    // Close the file pointer 
    fclose(fp); 
  
    return (0); 
}
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="Output" %}

```
Value of errno: 2
The error message is : No such file or directory
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
&#x20; นอกจากนี้ยังมีฟังก์ชัน ferror() และ clearerr() ที่ใช้ในการตรวจจับข้อผิดพลาดในการ stream   &#x20;

ศึกษาเพิ่มเติม :: [Error handling during file operations in C/C++](https://www.geeksforgeeks.org/error-handling-during-file-operations-in-c-c/?ref=rp)
{% endhint %}

### Exit Status

&#x20;    Exit Status จะต่างจาก errno, perror() และ strerror() ที่เป็นการแสดงผลข้อผิดพลาด เพื่อให้โปรแกรมสามารถทำงานต่อไปได้ แต่ Exit Status เป็นคำสั่งที่ใช้ในการออกจากโปรแกรม แบ่งออกเป็น 2 ประเภท คือ Exit Success และ Exit Failure ซึ่งต้องทำการ include  ก่อน จึงจะสามารถใช้คำสั่ง exit()

&#x20;    1\. Exit Success คือ การออกจากโปแกรมที่ไม่เกิดข้อผิดพลาด สามารถเลือกใช้ได้ 2 แบบ ดังต่อไปนี้

{% tabs %}
{% tab title="Syntax" %}

```
exit(EXIT_SUCCESS)
exit(0)
```

{% endtab %}
{% endtabs %}

{% hint style="danger" %}
สร้างไฟล์ file.txt ก่อน run code ดังต่อไปนี้
{% endhint %}

{% tabs %}
{% tab title="Example code C" %}

```c
// err_p2_1.c
#include <stdio.h> 
#include <stdio.h> 
  
int main() 
{ 
    FILE* file; 
  
    // opening the file in read-only mode 
    file = fopen("file.txt", "r"); 
  
    printf("File opening successful!"); 
  
    // EXIT_SUCCESS 
    exit(0); 
}
```

{% endtab %}

{% tab title="Example code C++" %}

```cpp
// err_p2_2.cpp
#include <iostream>
#include <stdlib.h>
using namespace std;
  
int main() 
{ 
    FILE* file; 
  
    // opening the file in read-only mode 
    file = fopen("myFile.txt", "r"); 
  
    cout << "File opening successful!" << endl; 
  
    // EXIT_SUCCESS 
    exit(0); 
}
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="Output" %}

```
File opening successful!
```

{% endtab %}
{% endtabs %}

&#x20;    2\. Exit Failure คือ การออกจากโปรแกรมที่เกิดข้อผิดพลาด สามารถเลือกใช้ได้ 2 แบบ ดังต่อไปนี้

{% tabs %}
{% tab title="Syntax" %}

```
exit(EXIT_FAILURE)
exit(1)
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="Example code C" %}

```c
// err_p2_3.c
#include <stdio.h> 
#include <stdlib.h>
  
int main() 
{ 
    FILE* file; 
  
    // open the file in read-only mode 
    file = fopen("myFile.txt", "r"); 
  
    if (file == NULL) { 
        printf("Error in opening file\n"); 
  
        // EXIT_FAILURE 
        exit(1); 
    } 
  
    // EXIT_SUCCESS 
    exit(0); 
} 
```

{% endtab %}

{% tab title="Example code C++" %}

```cpp
// err_p2_4.cpp
#include <iostream>
#include <stdlib.h>
using namespace std;
  
int main() 
{ 
    FILE* file; 
  
    // open the file in read-only mode 
    file = fopen("myFile.txt", "r"); 
  
    if (file == NULL) { 
        cout << "Error in opening file" << endl; 
  
        // EXIT_FAILURE 
        exit(1); 
    } 
  
    // EXIT_SUCCESS 
    exit(0); 
} 
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
&#x20;   สำหรับ exit(EXIT\_FAILURE) สามารถใช้จำนวนเต็มอื่นที่ไม่ใช่ 1 เพื่อระบุข้อผิดพลาดประเภทต่างๆ
{% endhint %}

แหล่งอ้างอิง ::

* .<https://www.tutorialspoint.com/cprogramming/c_error_handling.htm>
* <https://www.geeksforgeeks.org/error-handling-c-programs/>
* <https://en.cppreference.com/w/cpp/header/cerrno>
