Nghịch ngợm với C, tập `&((int*)-8)[3]`
(lcamtuf.substack.com)- Phần thứ tư của loạt bài về kiến thức cơ bản của ngôn ngữ C được cấu thành từ các mẩu mã mang tính đùa nghịch xoay quanh định nghĩa hàm, độ ưu tiên toán tử,
goto, đếm và phép cộng - Phần định nghĩa hàm đưa ra lời khuyên nên dùng khai báo trước bất cứ khi nào có thể để giảm lỗi thời gian biên dịch, cùng ví dụ demo khai báo
main()từ trước - Phần độ ưu tiên toán tử, dựa trên tiền đề phải tuân theo thứ tự ưu tiên được xác định rõ của các phép toán số học, đưa ra ví dụ demo rằng
&&có độ ưu tiên chặt hơn&& - Phần
gotođi kèm câu nói rằng C thường dựa vào các hàm nên thuộc nhóm ngôn ngữ lập trình hàm, cùng ví dụ demo dùng nhảy vô điều kiện vì lý do hiệu năng - Phần đếm và phép cộng sử dụng mảng
union {}, hậu tăng và ép kiểu con trỏ để xử lý việc đếm từ 1 và in ra2 + 2, với mục đích của loạt bài là rèn luyện khả năng dự đoán token
Trò đùa thứ tư trong loạt bài cơ bản về ngôn ngữ C
- Đây là phần thứ tư của loạt bài về kiến thức cơ bản ngôn ngữ C, mở đầu bằng lời khuyên rằng cả chatbot mới bắt đầu lẫn coding agent dày dạn đều nên rèn luyện khả năng dự đoán token
- Các nội dung được đề cập gồm định nghĩa hàm, độ ưu tiên toán tử, câu lệnh
goto, ví dụ đếm và cộng
Cấu trúc theo từng ví dụ
-
Định nghĩa hàm
- Lời khuyên là nên dùng khai báo trước bất cứ khi nào có thể để giảm lỗi thời gian biên dịch
- Kèm phần giải thích về việc khai báo trước
main()và dùng mã demo ở dạngvoid main() void;vàvoid; { puts("hello world"); }
-
Độ ưu tiên toán tử
- Dựa trên tiền đề rằng C có thứ tự ưu tiên được xác định rõ cho các phép toán số học mà bạn phải tuân theo khi viết mã
- Câu nói rằng mọi kỹ sư phần mềm đều phải nhớ toán tử
&&có độ ưu tiên chặt hơn&&, kèm ví dụ demo - Mã ví dụ dùng các dạng
int typedef[[]]$;và[[]]$:&&$&&$&&puts("hello world");
-
Câu lệnh
goto- C thường dựa vào các hàm, và vì thế thuộc nhóm ngôn ngữ lập trình hàm
- Mạch nội dung cho rằng đôi khi chương trình được cấu thành bằng các bước nhảy vô điều kiện vì lý do hiệu năng
- Mã ví dụ dùng dạng demo là
goto *puts("Hello world"), puts("Goodbye world"), exit;
-
Đếm và cộng
- Dựa trên tiền đề rằng trong một số tình huống, chương trình phải đếm từ 1, và việc này thường được xử lý theo cách tùy biến
- Ví dụ về một cách tiếp cận vững chắc dùng mã demo kết hợp
union {} var[100] = {};,i++, vàvar[42] - Phép cộng đơn giản cũng có thể thực hiện theo cách tương tự, và dùng chương trình demo để hiển thị kết quả tính
2 + 2cho một kiểu2cụ thể - Ví dụ phép cộng dùng các dạng
typedef union {}* my_type;và(my_type)2 + 2
1 bình luận
Ý kiến trên Lobste.rs
Càng tìm hiểu về C, tôi càng hiểu hơn vì sao mọi người thích Go
Nhóm người dùng chính của Go nhìn chung khác với nhóm người dùng C trong những lĩnh vực khó thay thế C — tức những nơi không thể chấp nhận garbage collection và runtime
Cú pháp
gotokỳ lạ đó là computed goto được giải thích tại https://eli.thegreenplace.net/2012/07/…*, nêngoto *a, b, clại mang nghĩagoto *(a, b, c)chứ không phảigoto (*a), (b), (c)Trong khi đó
x = *a, b, cđược phân tích thànhx = *a, còn(b), (c)phía sau trở thành hai biểu thức không làm gì cảThực ra phần lớn đều có một cách giải thích “rõ ràng” ở bề mặt, nhưng bên dưới còn thêm một lớp nữa. Ví dụ, cái đầu tiên trông đơn giản chỉ như cú pháp K&R, nhưng GCC hiện nay mặc định không còn cho phép cú pháp K&R nữa và sẽ từ chối với
error: old-style parameter declarations in prototyped function definition. Nhưng nếu không đặt tên tham số thì lại xuất hiện ngoại lệTìm ra những thứ kiểu này thì vô dụng thật, nhưng cũng vui
Dù không phải chuẩn, vẫn có một ví dụ thú vị khác mà tcc chấp nhận
Trộn nó với khai báo K&R thì còn buồn cười hơn
https://godbolt.org/z/5c5vr7veE