Lỗi “#include iostream.h #include conio.h” trong C++ và cách khắc phục

Việc sử dụng #include iostream.h#include conio.h trong các chương trình C++ hiện đại thường dẫn đến lỗi. Bài viết này sẽ giải thích lý do và cung cấp giải pháp thay thế.

Đoạn code dưới đây minh họa việc sử dụng các header lỗi thời này:

#define WIN32_LEAN_AND_MEAN
#define INITGUID 

#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <iostream.h>
#include <conio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <math.h>
#include <io.h>
#include <fcntl.h>
#include <ddraw.h>

#define WINDOW_CLASS_NAME "WINCLASS1"
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define SCREEN_BPP 8
#define MAX_COLORS 256

typedef unsigned short USHORT;
typedef unsigned short WORD;
typedef unsigned char UCHAR;
typedef unsigned char BYTE;

#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1: 0)
#define KEYUP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

#define DD_INIT_STRUCT(ddstruct) { memset ( &ddstruct,0,sizeof(ddstruct)); ddstruct.dwSize=(ddstruct); }

HWND main_window_handle = NULL;
HINSTANCE hinstance_app = NULL;

LPDIRECTDRAW7 lpdd = NULL;
LPDIRECTDRAWSURFACE7 lpddsprimary = NULL;
LPDIRECTDRAWSURFACE7 lpddsback = NULL;
LPDIRECTDRAWPALLETE lpddpal = NULL;
LPDIRECTDRAWCLIPPER lpddclipper = NULL;
PALETTEENTRY pallete[256];
PALETTEENTRY save_palette[256];
DDSURFACEDESC2 ddsd;
DDBLTFX ddbltfx;
DDSCAPS2 ddscaps;
HRESULT ddrval;
DWORD start_clock_count = 0;

int min_clip_x=0,max_clip_x=SCREEN_WIDTH-1, min_clip_y=0, max_clip_y=SCREEN_HEIGHT-1;
int screen_width = SCREEN_WIDTH, screen_height=SCREEN_HEIGHT, screen_bpp = SCREEN_BPP;
char buffer[80];

LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
    PAINTSTRUCT ps;
    HDC hdc;
    char buffer[80];

    switch(msg) {
        case WM_CREATE: {
            return(0);
        } break;

        case WM_PAINT: {
            hdc= BeginPaint(hwnd, &ps);
            EndPaint(hwnd, &ps);
            return(0);
        } break;

        case WM_DESTROY: {
            PostQuitMessage(0);
            return(0);
        } break;

        default: break;
    }

    return (DefWindowProc(hwnd, msg, wparam, lparam)); 
}

int Game_Main(void *parms = NULL, int num_parms = 0) {
    if (KEYDOWN(VK_ESCAPE)) SendMessage(main_window_handle, WM_CLOSE, 0,0);
    return(1);
}

int Game_Init(void *parms = NULL, int num_parms = 0) {
    if (FAILED(DirectDrawCreateEx(NULL, (void **)&lppd, IID_IDirectDraw7, NULL))) return(0);
    lpdd->SetCooperativeLevel(main_window_handle, DDSCL_NORMAL);
    return(1);
}

int Game_Shutdown(void *parms = NULL, int num_parms = 0) {
    if(lpdd) {
        lpdd->Release();
        lpdd=NULL;
    }
    return(1);
}

int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) {
    WNDCLASSEX winclass;
    HWND hwnd;
    MSG msg;
    HDC hdc;

    winclass.cbSize = sizeof(WNDCLASSEX);
    winclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
    winclass.lpfnWndProc = WindowProc;
    winclass.cbClsExtra = 0;
    winclass.cbWndExtra = 0;
    winclass.hInstance = hinstance;
    winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    winclass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
    winclass.lpszMenuName = NULL;
    winclass.lpszClassName = WINDOW_CLASS_NAME;
    winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    hinstance_app = hinstance;

    if (!RegisterClassEx(&winclass)) return(0);

    if (!(hwnd = CreateWindowEx(NULL, WINDOW_CLASS_NAME, "T3D Game Console", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0,0, 400,300, NULL, NULL, hinstance, NULL))) return(0);
    main_window_handle = hwnd;

    Game_Init();

    while(TRUE) {
        if (PeekMessage(&msg, NULL, 0,0,PM_REMOVE)) {
            if(msg.message == WM_QUIT) break;

            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        Game_Main();
    }

    Game_Shutdown();

    return(msg.wParam);
}

Vấn đề với iostream.hconio.h

  • iostream.h: Đây là phiên bản cũ của thư viện iostream trong C++. Phiên bản chuẩn hiện tại là <iostream> (không có .h). Việc sử dụng iostream.h có thể gây ra lỗi biên dịch, đặc biệt khi bạn sử dụng các trình biên dịch C++ hiện đại.
  • conio.h: Thư viện này không phải là một phần của chuẩn C++. Nó chủ yếu được sử dụng trong các trình biên dịch cũ như Turbo C++ và Borland C++. conio.h cung cấp các hàm liên quan đến điều khiển console, chẳng hạn như getch(), clrscr(), nhưng các hàm này không được đảm bảo hoạt động trên mọi hệ thống.

Giải pháp thay thế

  1. Thay thế iostream.h bằng <iostream>:

    • Thay đổi #include <iostream.h> thành #include <iostream>.
    • Thêm using namespace std; nếu bạn muốn sử dụng các đối tượng như coutcin mà không cần tiền tố std::.
  2. Thay thế conio.h:

    • Nếu bạn cần getch(): Hàm getch() dùng để đọc một ký tự từ bàn phím mà không cần nhấn Enter. Không có hàm tương đương chuẩn trong C++. Tuy nhiên, bạn có thể sử dụng các giải pháp thay thế phụ thuộc vào hệ điều hành:
      • Windows: Sử dụng _getch() từ <conio.h> (lưu ý dấu gạch dưới). Bạn cũng có thể sử dụng API Windows ReadConsoleInput(), nhưng phức tạp hơn.
      • Linux/macOS: Sử dụng thư viện ncurses hoặc các phương pháp tương tự để điều khiển terminal.
    • Nếu bạn cần clrscr(): Hàm clrscr() dùng để xóa màn hình console. Không có hàm tương đương chuẩn. Bạn có thể sử dụng các lệnh hệ thống:
      • Windows: system("cls");
      • Linux/macOS: system("clear");
    • Tổng quát: Nên tránh sử dụng các hàm không chuẩn như clrscr()getch() nếu bạn muốn chương trình của mình có khả năng tương thích cao. Thay vào đó, hãy sử dụng các thư viện và phương pháp chuẩn để xử lý đầu vào/đầu ra và điều khiển giao diện người dùng.

Ví dụ:

Alt text: Đoạn code C++ minh họa việc sử dụng <iostream>using namespace std; để xuất chuỗi “Hello, World!” ra màn hình.

#include <iostream>

using namespace std;

int main() {
  cout << "Hello, World!" << endl;
  return 0;
}

Ví dụ thay thế conio.h (Windows)

#include <iostream>
#include <conio.h> // Cần thiết cho _getch() trên Windows

using namespace std;

int main() {
  cout << "Press any key to continue..." << endl;
  _getch(); // Đợi người dùng nhấn một phím
  return 0;
}

Alt text: Giao diện dòng lệnh Windows đang chờ nhận một ký tự đầu vào từ người dùng sau khi hiển thị thông báo “Press any key to continue…”, sử dụng hàm _getch() từ conio.h.

Tóm tắt

Việc sử dụng #include iostream.h#include conio.h nên được tránh trong các chương trình C++ hiện đại. Thay vào đó, hãy sử dụng <iostream> và tìm các giải pháp thay thế chuẩn hoặc phụ thuộc vào hệ điều hành cho các hàm từ conio.h. Điều này sẽ giúp bạn viết code tương thích hơn và dễ bảo trì hơn. Việc thay thế các thư viện cũ bằng các thư viện hiện đại không chỉ giúp chương trình của bạn chạy ổn định hơn mà còn giúp bạn tiếp cận với những tính năng và cải tiến mới nhất của ngôn ngữ C++.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *