Bài 58.126 phút đọc
Cảnh báo của trình biên dịch
Sau bài này bạn sẽ làm được
- Bật bộ cờ cảnh báo đầy đủ
- Kể mười cảnh báo không nằm trong -Wall -Wextra
- Dùng -Werror trong tích hợp liên tục
- Tắt một cảnh báo cụ thể ở một chỗ cụ thể
Trình biên dịch là công cụ phân tích tĩnh mạnh nhất bạn đã có sẵn, và phần lớn khả năng của nó bị tắt theo mặc định. Bài này bật hết, và đo xem việc đó bắt thêm được bao nhiêu.
#-Wall không phải là all
sot.c, sáu vấn đề thật
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* 1. Chuyen doi thu hep im lang */
static void thu_hep(void) {
long lon = 3000000000L;
int nho = lon; /* mat du lieu */
double d = 3.99;
int i = d; /* cat phan thap phan */
printf("thu_hep: %d %d\n", nho, i);
}
/* 2. So sanh co dau va khong dau */
static void dau(void) {
int a = -1;
unsigned b = 1;
printf("dau: -1 < 1 la %s\n", (a < b) ? "dung" : "SAI");
}
/* 3. Khai bao cu kieu K&R, khong co nguyen mau */
static int cong(); /* () khong phai (void) */
/* 4. Bo cuc struct lang phi */
struct Xau { char a; double b; char c; };
/* 5. Ham khong lam gi */
static void ham_khong_doi(void) { }
/* 6. Bien an bien ngoai */
static int dem = 0;
static void an(void) {
int dem = 5; /* che bien toan cuc */
printf("an: %d\n", dem);
}
int main(void) {
thu_hep();
dau();
an();
printf("sizeof(struct Xau) = %d\n", (int)sizeof(struct Xau));
printf("cong = %d\n", cong(1, 2));
ham_khong_doi();
return 0;
}
static int cong(a, b) int a; int b; { return a + b; }terminal
gcc -std=c11 -Wall -Wextra -c sot.c -o /dev/null
sot.c: In function 'dau':
sot.c:19:38: warning: comparison of integer expressions of different signedness: 'int' and 'unsigned int' [-Wsign-compare]
printf("dau: -1 < 1 la %s\n", (a < b) ? "dung" : "SAI");
^
At top level:
sot.c:32:12: warning: 'dem' defined but not used [-Wunused-variable]
static int dem = 0;
^~~gcc -std=c11 -Wall -Wextra -c sot.c -o /dev/null 2>&1 | grep -c warning
2
#Bộ cờ đầy đủ
Makefile
CANH_BAO := -Wall -Wextra -Wpedantic \
-Wconversion -Wsign-conversion \
-Wshadow \
-Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition \
-Wcast-qual -Wcast-align \
-Wwrite-strings \
-Wredundant-decls -Wnested-externs \
-Wundef \
-Wdouble-promotion \
-Wformat=2 \
-Wnull-dereference \
-Wswitch-enum -Wswitch-default \
-Wfloat-equal \
-Wunreachable-code
CFLAGS := -std=c11 $(CANH_BAO) -gterminal
gcc -std=c11 $CANH_BAO -c sot.c -o /dev/null
sot.c:8:16: warning: overflow in conversion from 'long long int' to 'long int' changes value from '3000000000' to '-1294967296' [-Woverflow] sot.c:11:16: warning: conversion from 'double' to 'int' may change value [-Wfloat-conversion] sot.c:19:38: warning: comparison of integer expressions of different signedness: 'int' and 'unsigned int' [-Wsign-compare] sot.c:23:1: warning: function declaration isn't a prototype [-Wstrict-prototypes] sot.c:26:8: warning: padding struct size to alignment boundary [-Wpadded] sot.c:34:9: warning: declaration of 'dem' shadows a global declaration [-Wshadow] sot.c:47:12: warning: function declaration isn't a prototype [-Wstrict-prototypes] sot.c:47:12: warning: old-style function definition [-Wold-style-definition] sot.c:32:12: warning: 'dem' defined but not used [-Wunused-variable]
gcc -std=c11 $CANH_BAO -c sot.c -o /dev/null 2>&1 | grep -c 'warning:'
9
#Cảnh báo chuyển đổi
chuyen.c, năm chuyển đổi ngầm
#include <stddef.h>
#include <string.h>
int lay_do_dai(const char *s) { return strlen(s); } /* size_t -> int */
char lay_byte(int x) { return x; } /* int -> char */
unsigned lay_khong_dau(int x) { return x; } /* co dau -> khong dau */
float lay_float(double d) { return d; } /* double -> float */
int lay_tu_ll(long long v) { return v; } /* 64 -> 32 bit */terminal
gcc -std=c11 -Wall -Wextra -c chuyen.c -o /dev/null 2>&1 | grep -c warning
0
gcc -std=c11 -Wall -Wextra -Wconversion -Wsign-conversion -c chuyen.c -o /dev/null
chuyen.c:3:41: warning: conversion from 'size_t' {aka 'long long unsigned int'} to 'int' may change value [-Wconversion]
chuyen.c:4:41: warning: conversion from 'int' to 'char' may change value [-Wconversion]
chuyen.c:5:41: warning: conversion to 'unsigned int' from 'int' may change the sign of the result [-Wsign-conversion]
chuyen.c:6:41: warning: conversion from 'double' to 'float' may change value [-Wfloat-conversion]
chuyen.c:7:41: warning: conversion from 'long long int' to 'int' may change value [-Wconversion]terminal
# Vi sao 'long' khong phai lua chon an toan
./kt.exe
sizeof(int) = 4 sizeof(long) = 4 sizeof(long long) = 8 sizeof(size_t) = 8 sizeof(void *) = 8
#-Werror
terminal
gcc -std=c11 -Wall -Wextra -Wconversion -Werror -c tat_cuc_bo.c -o /dev/null
tat_cuc_bo.c:14:12: error: conversion from 'size_t' {aka 'long long unsigned int'} to 'int' may change value [-Werror=conversion]
return strlen(s);
^~~~~~~~~
cc1.exe: all warnings being treated as errorsecho $?
1
#Tắt một cảnh báo ở một chỗ
tat_cuc_bo.c
#include <stdio.h>
#include <string.h>
/* Ham nay CO Y chuyen size_t sang int, va ta biet chuoi luon ngan. */
static int do_dai_ngan(const char *s) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
return strlen(s); /* an toan: goi ham nay chi voi chuoi < 100 */
#pragma GCC diagnostic pop
}
/* Ham nay KHONG duoc tat, canh bao phai con */
static int do_dai_bat_ky(const char *s) {
return strlen(s);
}
int main(void) {
printf("%d %d\n", do_dai_ngan("abc"), do_dai_bat_ky("abcd"));
return 0;
}terminal
gcc -std=c11 -Wall -Wextra -Wconversion -c tat_cuc_bo.c -o /dev/null
tat_cuc_bo.c:14:12: warning: conversion from 'size_t' {aka 'long long unsigned int'} to 'int' may change value [-Wconversion]gcc -std=c11 -Wall -Wextra -Wconversion -c tat_cuc_bo.c -o /dev/null 2>&1 | grep -c 'warning:'
1
Tự làm thử
- Dịch dự án của bạn với
-Wall -Wextrarồi với bộ cờ đầy đủ, và so số cảnh báo. - Bật
-Wconversioncho một tệp và sửa hết cảnh báo trong tệp đó. - In ra
sizeofcủa các kiểu trên máy bạn và so với bảng LP64 và LLP64. - Thêm mục tiêu
kiem-canh-baodùng-Werrorvào Makefile và gọi nó từ CI. - Tìm một cảnh báo báo giả trong dự án và tắt nó bằng
push,ignored,popkèm bình luận. - Đếm mọi phép ép kiểu thu hẹp trong dự án và kiểm tra xem có bao nhiêu cái thật sự đã kiểm tra phạm vi.
Trình chấm điểm tự động sẽ được bổ sung ở giai đoạn sau. Hiện tại bạn tự chạy thử trên máy.
Tóm tắt
-Wall -Wextrabắt được hai trên sáu vấn đề trong ví dụ; bộ cờ đầy đủ bắt được chín cảnh báo.-Wconversionvà-Wsign-conversionlà hai cờ giá trị nhất không nằm trong-Wall.longlà 32 bit trên Windows; dùngsize_tvà các kiểu trongstdint.h.-Werrortrong CI, không phải trong Makefile mặc định; nhưng bốn cảnh báo nguy hiểm nên là lỗi ở mọi nơi.- Tắt cảnh báo phải có
pushvàpop, phạm vi nhỏ nhất, và một bình luận nói vì sao an toàn.