Search…

Compiler Warning C4996 và C Run-time Library hay _CRT_SECURE_NO_WARNINGS (CRT)

04/09/20204 min read
Compiler warning C4996 là cảnh báo thường gặp khi sử dụng các hàm strcpy hay scanf trong Visual Studio từ bản 2012 trở đi. Bài viết sẽ giúp bạn hiểu rõ và khắc phục cảnh báo này với _CRT_SECURE_NO_WARNINGS hay còn gọi CRT.

Compiler warning C4996 là một trong những cảnh báo thường gặp khi thao tác với các hàm có liên quan tới thư viện CRT của Visual Studio từ phiên bản 2012 trở đi.

Bài viết giới thiệu đôi nét về CRT và cách khắc phục cảnh báo C4996.

Môi trường thử nghiệm

  • Visual Studio 2012 (C++) trở lên.

Nguyên nhân dẫn đến cảnh báo C4996

CRT là một phần của thư viện chuẩn của C++ được kết hợp với thư viện chuẩn ISO C99, CRT quản lí các hàm có liên quan tới thời gian thực thi (thời gian chạy file .exe). Tức là các hàm này phải có sự tác động từ bên ngoài vào. Ví dụ: trong hàm scanf() sau khi bạn biên dịch xong và cho chạy chương trình thì thời gian mà hàm scanf chờ lấy dữ liệu vào chính là thời gian thực thi.

Với các hàm như vậy khi compile có thể không có lỗi nhưng lại có thể phát sinh ra lỗi khi bạn chạy chương trình tùy thuộc vào dữ liệu nhập vào.

Ví dụ: trong hàm strcpy(src, des) dùng sao chép chuỗi des qua chuỗi src sẽ có trường hợp chuỗi src không đủ vùng nhớ để chứa hết chuỗi des, lúc đó chương trình sẽ bị lỗi và buộc phải dừng lại.

Những lỗi về thời gian thực thi có thể gây ra hậu quả nghiêm trọng vì file thực thi bị buộc dừng đột ngột trong khi vẫn chưa chạy đến dòng lệnh đóng chương trình lại, máy tính sẽ nhận diện rằng file này vẫn còn đang mở và bạn không thể mở nó lại một lần nữa trừ khi tắt máy khởi động lại hoặc cho ra kết quả sai.

Từ Visual Studio 2012 trở đi, thư viên CRT đã được bổ sung thêm các hàm mới với tính năng tương tự hàm gốc hỗ trợ giảm thiểu các lỗi như trên, và các hàm gốc sẽ bị đánh dấu là không an toàn. Điều này dẫn đến việc sử dụng các hàm gốc thì compiler sẽ bật cảnh báo nhắc nhở là hàm này sẽ có thể dẫn đến lỗi trong quá trình chạy. Đó chính là Compiler Warning C4996.

Các thể hiện cụ thể

Khi bạn sử dụng các hàm như scanf, fopen, … thường bị compiler "ép" sử dụng scanf_s, fopen_s, … và chúng ta sẽ thường thắc mắc là tại sao phải sử dụng scanf_s thay vì scanf?

STDIO_C4996_Example1

Các cách giải quyết vấn đề

Nếu bạn đọc kỹ phần cảnh báo này sẽ thấy Visual Studio cũng đã hướng dẫn chúng ta 2 hướng giải quyết vấn đề này.

Cách 1 - Dùng các hàm mới

Dùng hàm mới hơn, được đánh dấu là "safe" bằng cách thêm "_s" phía sau hàm gốc. Tuy nhiên, các hàm này chỉ có trên các sản phẩm từ Visual Studio, và sẽ không có trên các trình biên dịch khác như GCC, Xcode.

Lợi ích và nhược điểm của cách này là code không cần giải quyết vấn đề, tuy nhiên nếu code này sử dụng cho đa nền tảng thì ta lại phải sửa lại code nếu sử dụng trên các nền tảng khác hoặc cần viết lại các hàm bao bọc.

Cách 2 - Vẫn sử dụng các hàm gốc

Nguyên tắc là ta phải thông báo được cho trình biên dịch biết và bỏ qua thông báo này, nghĩa là ta hiểu rất rõ những gì ta đang làm và chấp nhận rủi ro bằng "cờ" _CRT_SECURE_NO_WARNINGS.

Thay đổi Properties của project bằng GUI

Nhấp phải tại tên Project chọn Properties → Configuration → C/C++ → Preprocessor → trong mục Preprocessos Definitions phía bên phải thêm vào dòng _CRT_SECURE_NO_WARNINGS → OK.

STDIO_C4996_Example2

Như vậy ta “nhắn gửi” với trình biên dịch rằng, ta đang hiểu rõ những gì đang diễn ra và chấp nhận rủi ro nếu có.

Sử dụng definition directive - #define _CRT_SECURE_NO_WARNINGS

Trước khi sử dụng các hàm CRT như scanf, fopen, strcpy, ... ta có thể đưa thêm cờ này vào đầu file.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
	char key[8];
	scanf(key, %s);

	return 0;
}

Phụ lục

config.h

Thông thường khi khởi tạo 1 project, bạn có thể tạo 1 file config.h và lưu toàn bộ các #define cần thiết trong đó, với nguyên tắc tất cả các file trong project phải #include "config.h"

Sử dụng #pragma để tắt cảnh báo C4996

Chỉ thị #pragma token-string cho phép ta chỉ thị cho compiler biên dịch chương trình theo một tùy chọn đặc biệt nào đó, mỗi token-string có một tham số và chức năng riêng biệt, các token-string này tùy thuộc vào từng compiler.

Trong bài viết chỉ đề cập Compiler C/C++ của Microsoft. Để tắt cảnh báo C4996 chúng ta có thể sử dụng chỉ thị #pragma sau và đặt nó ở đầu file: #pragma warning(disable:4996).

Tham khảo thêm về #pragma trong Visual Studio trên MSDN.

IO Stream

IO Stream Co., Ltd

30 Trinh Dinh Thao, Hoa Thanh ward, Tan Phu district, Ho Chi Minh city, Vietnam
+84 28 22 00 11 12
developer@iostream.co

383/1 Quang Trung, ward 10, Go Vap district, Ho Chi Minh city
Business license number: 0311563559 issued by the Department of Planning and Investment of Ho Chi Minh City on February 23, 2012

©IO Stream, 2013 - 2024