Modern C phiên bản C23
(gustedt.wordpress.com)- Bản sửa đổi Modern C được cập nhật theo chuẩn C mới đã được phát hành để tải xuống miễn phí, giúp người học và người tra cứu ngôn ngữ C xem lại tài liệu theo chuẩn C23
- Trọng tâm của lần sửa đổi là phản ánh C23, tập trung vào việc hỗ trợ chuyển đổi sang chuẩn mới, đồng bộ với quy trình và thời điểm xuất bản của ISO
- Các bản phát hành mới của những trình biên dịch lớn đã triển khai hầu hết tính năng của C23, nên các thay đổi trong sách không chỉ là phần giới thiệu mang tính thử nghiệm mà còn gắn với môi trường sử dụng thực tế
- Các thay đổi về ngôn ngữ và thư viện như
_BitInt(N),nullptr,auto,typeof,constexprđược phản ánh rộng rãi, ảnh hưởng cả đến cách viết mã C hiện có - Phụ lục chuyển đổi và các header include tạm thời đã được bổ sung để có thể thử ngay trên các nền tảng hiện có, nhưng MEAP của Manning vẫn đang tiếp diễn
Tài liệu miễn phí công khai và tài liệu chuẩn
- Modern C phiên bản C23 có thể được tải xuống miễn phí
- Tải xuống: https://hal.inria.fr/hal-02383654
- Có thể tìm thấy các tài liệu liên quan trên trang riêng của cuốn sách
- Trang riêng: https://gustedt.gitlabpages.inria.fr/modern-c/
- Liên kết tải xuống các ví dụ mã đi kèm sách cũng có trên trang này
- Bản sửa đổi đã chỉnh sửa nhiều phần giải thích, nhưng mục tiêu cốt lõi là phản ánh chuẩn C mới, C23
- Trong số các tài liệu có thể truy cập công khai, tài liệu gần nhất với nội dung của chuẩn mới là PDF N3220
- Các bản phát hành mới của những trình biên dịch lớn đã triển khai hầu hết các tính năng mới mà C23 mang lại
Thay đổi ngôn ngữ C23 và hỗ trợ chuyển đổi
- Các thay đổi liên quan đến số nguyên chiếm tỷ trọng lớn
- Bổ sung kiểu có độ chính xác bit mới
_BitInt(N) - Bổ sung các header thư viện C mới cho phép tính số học có kiểm tra tràn và thao tác bit
- Phản ánh khả năng có kiểu 128 bit trên các kiến trúc hiện đại
- Bao gồm cả những cải tiến thực chất đối với kiểu enum
- Bổ sung kiểu có độ chính xác bit mới
- Cũng bao gồm các khái niệm mới khác của C23
- Hằng
nullptrvà kiểu nền tảng của nó - Chú thích cú pháp thông qua attributes
- Công cụ lập trình generic theo kiểu dữ liệu, bao gồm
autovàtypeof - Khởi tạo mặc định bằng
{}cũng áp dụng cho mảng có độ dài biến đổi constexprcho các hằng có tên thuộc mọi kiểu
- Hằng
- Tài liệu mới còn đề cập đến biểu thức phức hợp, lambda, “quốc tế hóa” và cách tiếp cận toàn diện đối với lỗi chương trình
- Phụ lục và header include tạm thời đã được bổ sung để có thể bắt đầu dùng C23 ngay trên các nền tảng hiện có
- MEAP cho phiên bản mới của Manning vẫn đang mở
- MEAP: https://www.manning.com/books/modern-c-third-edition
- Thời điểm xuất bản cuối cùng của phiên bản C23 do Manning phát hành vẫn chưa được biết
1 bình luận
Ý kiến trên Hacker News
Khác với little endian, thứ tự lưu trữ trên máy của tôi, cách biểu diễn đặt byte bậc cao lên trước được gọi là big endian; nhưng nói rằng cả hai đều được dùng phổ biến trên các bộ xử lý hiện đại thì hơi phóng đại, vì ngoài s390x gần như chẳng còn gì
Chắc sắp có các bình luận về những kiến trúc big endian ngách/đã chết yểu mà mọi người yêu thích
Như một bình luận hàng đầu khác đã nói, “hiện đại” không nhất thiết có nghĩa là phổ biến hay được dùng rộng rãi
AIX và IBM i có lẽ không còn sôi động như mainframe của IBM, nhưng có thể xem AIX còn sống hơn cả Solaris hay HP/UX, nhất là khi so với vô số Unix thương mại trước đây. IBM i cũng đang cầm cự, nhưng vẫn sống hơn nhiều so với các nền tảng midrange legacy cạnh tranh như HP MPE, vốn đã chính thức bị nhà cung cấp chấm dứt hỗ trợ
Khía cạnh quan trọng nhất của C là tính di động. Điểm cốt lõi là chạy được từ các vi điều khiển nhỏ đến gần như mọi nền tảng điện toán, nhưng tôi nghi ngờ liệu phiên bản C mới có được chấp nhận đến mức đó không
Nếu muốn dùng thứ tiên tiến nhất, tôi nghĩ mình sẽ chọn C++2x hoặc Rust hơn là C. Tôi có bỏ sót điều gì không? Tôi tò mò lợi ích mà cái gọi là C hiện đại này mang lại là gì
Nếu muốn thứ tiên tiến, tôi khuyên dùng Zig. Độ phức tạp của ngôn ngữ thấp hơn nhiều so với C++ hiện đại và Rust. Một tác dụng phụ tốt nhưng ít nổi bật của C23 là nó làm các cú pháp như
... = {}và{0}khớp hơn với C++, khiến người bảo trì thư viện C đỡ phiền hơn khi hỗ trợ những người muốn build mã C bằng trình biên dịch C++0bđược dùng rộng rãi trong thế giới vi điều khiểnToolchain cho vi điều khiển phần lớn được xây trên GCC nên gần như nhận tính năng miễn phí. Vẫn có các trình biên dịch C độc quyền luôn tụt hậu, nhưng chúng không còn quan trọng như 20 năm trước
Nếu không nhắm đến embedded hoặc một tập kiến trúc rất rộng, cũng chẳng có lý do gì để không dùng C23 ngay từ hôm nay
thread_localđã được dùng trên vài nền tảng vi điều khiển, nhưng trước C11 thì hoàn toàn bất hợp pháp. Dù vậy, nó đơn giản hóa quản lý bộ nhớ trong môi trường có luồng rất nhiềuCó cần phải bước hẳn sang thế giới C++ chỉ vì điều đó không?
Cá nhân tôi thấy những thứ như
guard,defer,auto,constexpr,nullptrlàm C phức tạp hơn nhiều. Tôi chọn C vì cần sự đơn giản; nếu muốn phức tạp thì thường, dù không muốn, tôi sẽ chọn C++, hoặc thà chọn Go, còn nếu là server thì chọn Elixir_BitInt(N)cũng xấu, may mà nó gợi nhớ đến_Boolnay đã thànhbool.constexprvànullptrmang mùi C++ quá nặng. Dù vậy Modern C là một cuốn sách tuyệt vời, và tôi đã dùng rất tốt cho C99, thứ tôi dự định tiếp tục bám lấyNULLcó vấn đề gì sẽ có câu trả lời nếu đọc tài liệu liên quan, nhờ một trong số ít ưu điểm của chuẩn hóa ISO: https://wg21.link/p2312Tóm lại, khi truyền đối số
NULLvào macro type-generic có thể sinh ra kết quả bất ngờ, và trạng thái của các biểu thức điều kiện như(1 ? 0 : NULL)và(1 ? 1 : NULL)phụ thuộc vào cách định nghĩaNULL. Ngoài ra, truyềnNULLvào hàm variadic đang kỳ vọng con trỏ có thể gây hậu quả nghiêm trọng. Trên nhiều kiến trúc ngày nay, kích thướcintvàvoid*khác nhau, nên nếuNULLchỉ là0thì đối số có kích thước sai sẽ được truyền vào hàmGiống như xây nhà. Búa và tua vít rất đơn giản, còn cần cẩu cực kỳ phức tạp, nhưng thứ làm việc xây nhà đơn giản hơn lại là cần cẩu. Nếu chỉ dùng búa và tua vít để xây nhà thì phải nghĩ ra một quy trình cực kỳ phức tạp
Ngôn ngữ lập trình cũng vậy. Tạo container generic trong C++ là chuyện nhỏ, nhưng trong C thì rất khó. Có thể phần nào bắt chước bằng
void *và ép kiểu thủ công, nhưng rườm rà, dễ lỗi và làm mã phức tạp hơnstd::sortvàqsortcũng tương tự. Nhờ sức mạnh của template và function object, phần triển khai đơn giản hơn và nhanh hơn. Không cần truyềnvoid *rồi dereference lúc chạy, và có thể đặt phép so sánh ngay trong định nghĩa hàm. Không có lời gọi gián tiếp, không truyền qua stack, thậm chí còn có thể inline hàm so sánh. Độ phức tạp của ngôn ngữ không đồng nghĩa với độ phức tạp của triển khaiautochủ yếu hữu ích khi đụng đến macro type-generic, nhưng trong mã thông thường thì tốt nhất là không dùng. Hy vọng tránh được cơn điên almost always auto từng thịnh hành một thời trong thế giới C++Đáng tiếc là mỗi trình biên dịch lại có khác biệt nhỏ. Theo tôi nhớ, Clang triển khai
autokiểu C++, còn GCC triển khaiautokiểu C, nên có khác biệt tinh vi với con trỏauto. Tôi không biết khác biệt đó giờ đã được sửa chưa_BitInt(N)thường không được dùng trực tiếp mà sẽtypedefthành độ rộng cần thiết. Ví dụ dùng nhưtypedef _BitInt(2) u2;. Cú pháp xấu như_Blà cần thiết vì tổ hợp dấu gạch dưới theo sau bởi chữ hoa được chuẩn C dành riêng, để khi thêm tính năng nhỏ vào ngôn ngữ không va chạm với mã hiện có. Tên_Boolcũng vì lý do tương tự. Theo tôi biết,deferthực ra đã không vào C23Định nghĩa trước đây thậm chí không chỉ rõ
NULLlà con trỏ hay số nguyên. Vì vậy, trên những nền tảng không tuân theo yêu cầu((void*)0)của POSIX, đó là một cái bẫy dưới chân không phải kiểu con trỏ cũng chẳng phải kích thước con trỏ.Việc
constexprvànullptrmang mùi C++ có lẽ là vì chúng được nhập ngược từ C++. Dù vậy vẫn có thể tiếp tục dùngNULL, và nhìn bề ngoài có vẻ nó đã được định nghĩa lại thànhnullptr.execlp("echo", "echo", "Hello, world!", NULL);Đoạn mã này không có lỗi đó:
execlp("echo", "echo", "Hello, world!", nullptr);Cách này cũng ổn:
execlp("echo", "echo", "Hello, world!", (char *)NULL);Định hỏi xem có danh sách sách C hay nào không thì tự tìm được câu trả lời. Ở đây Modern C được xếp vào mức trung cấp.
https://stackoverflow.com/questions/562303/the-definitive-c-...
Với vai trò sách đồng hành C hiện đại cho K&R, tôi cho rằng 21st Century C của Ben Klemens và C Programming: A Modern Approach của King là những lựa chọn thay thế dễ tiếp cận hơn.
Cá nhân tôi thích Effective C hơn Modern C. Modern C rất chặt chẽ, đọc giống một bản đặc tả ngôn ngữ có chú thích, thứ có thể cần thiết với chuyên gia, nhưng với người chỉ dùng C nhẹ nhàng như tôi thì khá nhàm chán.
Tôi khá thích một số phần mở rộng High C của Metaware.
https://news.ycombinator.com/item?id=41647843
https://news.ycombinator.com/item?id=38938402
Hơn một năm qua tôi dùng C++ hiện đại cho một dự án cá nhân là trình thông dịch ngôn ngữ, nhưng vì gánh nặng tinh thần và vấn đề công cụ của C++, tôi cứ nghĩ đến việc chuyển sang C. IntelliSense của Visual Studio đến giờ vẫn gần như không hoạt động khi dùng module C++20, và do những thất bại của ngôn ngữ, quá nhiều thứ bị đẩy ra interface khiến thời gian biên dịch cũng trở nên khó coi.
Ngược lại, tôi đã quá quen với class, hàm thành viên, lập trình generic, namespace, nên cũng có cảm giác mình đã mắc kẹt rồi.
Với nhu cầu đó, bạn đã cân nhắc C# chưa? Visual Studio hợp với C# hơn nhiều.
Khi nhấp vào liên kết mục lục ở thanh bên trong macOS Preview, chúng không hoạt động đúng.
Chỉ mới vài năm gần đây tôi mới có thể tin rằng các trình biên dịch C đều hỗ trợ C99 trong thư viện mình đang duy trì: https://github.com/eyalroz/printf
Nhưng rồi chỉ vài năm sau, đúng như dự đoán, lại có một issue được mở để yêu cầu tương thích C89 vì một toolchain nhúng cổ lỗ sĩ nào đó. Vì vậy C23 thì hay đấy, nhưng cảm giác là khoảng 20 năm nữa hãy nói tiếp.
Có ai có thể link một bài giải thích, ở góc độ thực tế, vì sao C về cơ bản bị kẹt ở C99 không? Trong các dự án đáng bàn, hầu như không thấy dự án nào tận dụng tính năng sau C11.
Vì C trên thực tế đã bị đóng băng trong nhiều thập kỷ, có vẻ cộng đồng người dùng cũng tự chọn lọc thành những người thích C đúng như hiện tại và không ngại hỗ trợ các trình biên dịch tạp nham cổ xưa. Những ai mất kiên nhẫn hoặc muốn một ngôn ngữ của thế kỷ 21 đã chuyển sang C++/Rust/Zig, v.v.
Vào khoảng năm 2010, MSVC vẫn rất quan trọng, điều này nghe có vẻ lạ nếu nhìn từ góc độ ngày nay khi phần lớn lập trình viên dường như đã chuyển sang Linux. Mặt khác, cũng không có nhiều dự án thực sự cần các tính năng C11. C11 còn lấy mất VLA khỏi C99, nhưng đó không phải là mất mát đáng tiếc lắm. C23 có thể là phiên bản đầu tiên kể từ C99 mà nhiều codebase C thực sự đáng nâng cấp lên.