Tại sao có quá ít trình biên dịch C?


72

C là một trong những ngôn ngữ được sử dụng rộng rãi nhất trên thế giới. Nó chiếm một tỷ lệ lớn của mã hiện có và tiếp tục được sử dụng cho một lượng lớn mã mới. Nó được người dùng yêu thích, nó được truyền tải rộng rãi đến mức có thể chạy C theo nhiều định nghĩa không chính thức của một nền tảng và được người hâm mộ ca ngợi là ngôn ngữ "nhỏ" với bộ tính năng tương đối sạch.

Vậy tất cả các trình biên dịch ở đâu?

Trên máy tính để bàn, có hai (thực tế) hai : GCC và Clang. Nghĩ về nó trong vài giây có lẽ bạn cũng sẽ nhớ Intel tồn tại. Có một số ít người khác, quá mơ hồ để người bình thường đặt tên và hầu như không bận tâm đến việc hỗ trợ phiên bản ngôn ngữ gần đây (hoặc thường là một tập hợp ngôn ngữ được xác định rõ, chỉ là "tập hợp con"). Một nửa số thành viên của danh sách này là chú thích lịch sử; hầu hết những người còn lại rất chuyên môn và vẫn không thực sự thực hiện toàn bộ ngôn ngữ. Rất ít thực sự có vẻ là nguồn mở.

Scheme và Forth - các ngôn ngữ nhỏ khác được người hâm mộ yêu thích vì nó - có thể có nhiều trình biên dịch hơn người dùng thực tế. Ngay cả một cái gì đó như SML có nhiều cách triển khai "nghiêm túc" hơn so với C. Trong khi thông báo về trình biên dịch C mới (chưa hoàn thành) nhằm xác minh thực sự thấy một số phản hồi khá tiêu cực và các triển khai kỳ cựu đấu tranh để có đủ người đóng góp để bắt kịp C99.

Tại sao? Thực hiện C có khó không? Nó không phải là C ++. Có phải người dùng chỉ đơn giản là có một ý tưởng rất sai lệch về nhóm phức tạp mà nó rơi vào (nghĩa là nó thực sự gần với C ++ hơn Scheme)?


61
MSVC vẫn được tính, ít nhất là một trình biên dịch C89. Có lẽ phổ biến hơn cả Intel.
Rufflewind

22
Wikipedia liệt kê khá nhiều trình biên dịch C. Chúng trở nên rất phổ biến khi bạn thấy mình trong vương quốc nhúng.

113
bạn cần bao nhiêu trình biên dịch để biên dịch mã C?
Bryan Chen

76
Câu hỏi được dựa trên một tiền đề sai. Các thiết bị tương tự, armcc, Trình biên dịch C của Bruce, Trình biên dịch chéo Bare-C, trình biên dịch Borland, trình biên dịch clang, trình biên dịch Cosmic C, trình biên dịch CodeWar Warrior, trình biên dịch dokto, trình biên dịch Ericsson và tôi thậm chí không nằm ngoài năm chữ cái đầu tiên của bảng chữ cái chưa. Có một số lượng lớn trình biên dịch C cực kỳ lớn . Câu hỏi đặt ra là "tại sao có quá ít trình biên dịch C, nếu chúng ta không tính vài chục trình biên dịch C thực sự này?" Bạn đã xác định phần lớn các trình biên dịch C là không thú vị, đó là lý do tại sao không có nhiều trình biên dịch.
Eric Lippert

19
Câu hỏi "Tại sao" là câu hỏi tồi cho trang web này vào thời điểm tốt nhất và "tại sao không?" Câu hỏi tệ hơn. Nếu tôi gặp bạn tại một bữa tiệc và hỏi "vậy, tại sao bạn không đua thuyền buồm?" Tôi nghĩ rằng bạn đúng là một câu hỏi kỳ lạ. Bạn không cần phải đưa ra lời biện minh cho việc KHÔNG tham gia vào một sở thích khó khăn về mặt kỹ thuật, rủi ro về thể chất và rất tốn kém. Viết bất kỳ phần mềm không tầm thường nào đều tốn kém, khó khăn và rủi ro và do đó đòi hỏi một động lực rất lớn . Một câu hỏi tốt hơn sẽ là "tại sao có nhiều trình biên dịch C?" Điều đáng ngạc nhiên là có nhiều hơn một.
Eric Lippert

Câu trả lời:


153

Ngày nay, bạn cần một trình biên dịch C thực sự để trở thành một trình biên dịch tối ưu hóa , đáng chú ý vì C không còn là ngôn ngữ gần với phần cứng, bởi vì các bộ xử lý hiện tại rất phức tạp ( không theo thứ tự , đường ống , siêu thanh , với bộ đệm & TLB phức tạp , do đó cần lập lịch hướng dẫn , v.v ...). Bộ xử lý x86 ngày nay không giống như bộ xử lý i386 của thế kỷ trước, ngay cả khi cả hai đều có thể chạy cùng một mã máy. Xem C không phải là ngôn ngữ cấp thấp (Máy tính của bạn không phải là bài viết nhanh PDP-11) của David Chisnall.

Rất ít người đang sử dụng các trình biên dịch C không tối ưu hóa ngây thơ như tinycc hoặc nwcc , vì chúng tạo ra mã chậm hơn nhiều lần so với các trình biên dịch tối ưu hóa có thể cung cấp.

Mã hóa một trình biên dịch tối ưu hóa là khó khăn. Lưu ý rằng cả GCC và Clang đều tối ưu hóa một số biểu diễn mã "trung lập ngôn ngữ nguồn" (Gimple cho GCC, LLVM cho Clang). Sự phức tạp của một trình biên dịch C tốt không nằm trong giai đoạn phân tích cú pháp!

Cụ thể, việc tạo một trình biên dịch C ++ không khó hơn nhiều so với tạo một trình biên dịch C: phân tích C ++ và chuyển đổi nó thành một số biểu diễn mã nội bộ rất phức tạp (vì đặc tả C ++ rất phức tạp), nhưng được hiểu rõ, nhưng các phần tối ưu hóa thậm chí còn nhiều hơn phức tạp (bên trong GCC: tối ưu hóa trung cấp, trung lập ngôn ngữ nguồn và bộ xử lý đích, tạo thành phần lớn trình biên dịch, phần còn lại được cân bằng giữa các giao diện người dùng cho một số ngôn ngữ và back-end cho một số bộ xử lý). Do đó, hầu hết các trình biên dịch C tối ưu hóa cũng có thể biên dịch một số ngôn ngữ khác, như C ++, Fortran, D, ... Các phần cụ thể C ++ của GCC chiếm khoảng 20% ​​trình biên dịch ...

Ngoài ra, C (hoặc C ++) được sử dụng rộng rãi đến mức mọi người mong đợi mã của họ có thể biên dịch được ngay cả khi nó không tuân theo chính xác các tiêu chuẩn chính thức, không xác định chính xác đủ ngữ nghĩa của ngôn ngữ (vì vậy mỗi trình biên dịch có thể có cách hiểu riêng của nó). Cũng xem xét trình biên dịch C đã chứng minh CompCert và trình phân tích tĩnh Frama-C , công ty quan tâm đến ngữ nghĩa chính thức hơn của C.

Và tối ưu hóa là một hiện tượng dài hạn : thực hiện một vài tối ưu hóa đơn giản là dễ dàng, nhưng chúng sẽ không làm cho trình biên dịch cạnh tranh! Bạn cần thực hiện rất nhiều tối ưu hóa khác nhau, và sắp xếp và kết hợp chúng một cách khéo léo, để có được một trình biên dịch trong thế giới thực có tính cạnh tranh. Nói cách khác, một trình biên dịch tối ưu hóa trong thế giới thực phải là một phần mềm phức tạp. BTW, cả GCC và Clang / LLVM đều có một số trình tạo mã C / C ++ chuyên dụng nội bộ. Và cả hai đều là những con thú khổng lồ (vài triệu dòng mã nguồn, với tốc độ tăng trưởng vài phần trăm mỗi năm) với cộng đồng nhà phát triển lớn (vài trăm người, làm việc chủ yếu toàn thời gian, hoặc ít nhất là một nửa thời gian).

Chú ý rằng có không có (theo sự hiểu biết của tôi) đa luồng C biên dịch, ngay cả khi một số bộ phận của một trình biên dịch có thể chạy song song (tối ưu hóa ví dụ như trong nội bộ thủ tục, đăng ký phân bổ, kế hoạch giảng dạy ...). Và xây dựng song song với make -jkhông phải lúc nào cũng đủ (đặc biệt là với LTO ).

Ngoài ra, rất khó để được tài trợ cho việc mã hóa trình biên dịch C từ đầu, và một nỗ lực như vậy cần phải kéo dài vài năm. Cuối cùng, hầu hết các trình biên dịch C hoặc C ++ đều là phần mềm miễn phí ngày nay (không còn thị trường cho các trình biên dịch độc quyền mới được bán bởi các công ty khởi nghiệp) hoặc ít nhất là các hàng hóa độc quyền (như Microsoft Visual C ++ ) và là một phần mềm miễn phí gần như được yêu cầu cho các trình biên dịch ( bởi vì họ cần sự đóng góp từ nhiều tổ chức khác nhau).

Tôi rất vui khi nhận được tài trợ để làm việc trên trình biên dịch C từ đầu như phần mềm miễn phí, nhưng tôi không đủ ngây thơ để tin rằng điều đó là có thể ngày hôm nay!


14
(there is no more a market for proprietary compilersNói điều đó với nhóm Visual Studio ...
Mason Wheeler

18
Microsoft có độc quyền. Tôi có nghĩa là các công ty nhỏ phát triển trình biên dịch C mới sẽ không bán được nhiều. Bạn có thể kể tên một đối thủ cạnh tranh độc quyền gần đây với MSVC không?
Basile Starynkevitch

12
Có nhiều trình biên dịch độc quyền trong thế giới HPC. PGCC, NAG và ICC được sử dụng rộng rãi nhất.
Davidmh

37
@MasonWheeler: VS được tặng miễn phí ngày nay (như trong bia). Các phiên bản không miễn phí thêm công cụ, nhưng trình biên dịch C trong VS2013 giống nhau trong tất cả các phiên bản. Không có thị trường, thậm chí không có cho họ.
MSalters

3
Nhưng cả GCC & LLVM đều đang hoạt động trên các biểu diễn thấp hơn nhiều và chúng tối ưu hóa mã C ++ & C (& Ada & Fortran, cho GCC) tương tự. Ngược lại, tôi sẽ nói rằng C ++ yêu cầu tối ưu hóa nhiều hơn (đáng chú ý là khi biên dịch mã bằng STL của nó) so với C!
Basile Starynkevitch

70

Tôi muốn tranh luận về giả định cơ bản của bạn rằng chỉ có một số ít triển khai C.

Tôi thậm chí không biết C, tôi không sử dụng C, tôi không phải là thành viên của cộng đồng C, tuy nhiên, thậm chí tôi biết nhiều hơn so với một vài trình biên dịch mà bạn đề cập.

Đầu tiên và quan trọng nhất, có trình biên dịch có thể lùn hoàn toàn cả GCC và Clang trên máy tính để bàn: Microsoft Visual C. Bất chấp sự xâm nhập mà cả OSX và Linux đã tạo ra trên máy tính để bàn và thị trường mà iOS và Android đã "đánh cắp" cách xa người dùng máy tính để bàn truyền thống trước đây, Windows vẫn hệ điều hành máy tính để bàn thống trị và phần lớn các chương trình máy tính để bàn Windows có thể được biên dịch bằng các công cụ của Microsoft.

Theo truyền thống, mỗi nhà cung cấp hệ điều hành và mọi nhà cung cấp chip đều có trình biên dịch riêng. Microsoft, với tư cách là nhà cung cấp hệ điều hành, có Microsoft Visual C. IBM, vừa là nhà cung cấp hệ điều hành vừa là nhà cung cấp chip, có XLC (là trình biên dịch hệ thống mặc định cho AIX và trình biên dịch có cả AIX và i / OS được biên dịch) . Intel có trình biên dịch riêng. Sun / Oracle có trình biên dịch riêng trong Sun Studio.

Sau đó, có các nhà cung cấp trình biên dịch hiệu năng cao như PathScale và Nhóm Portland, có trình biên dịch (và thư viện OpenMP) được sử dụng để đánh số.

Mars kỹ thuật số vẫn còn trong kinh doanh. Tôi tin rằng Walter Bright có sự khác biệt duy nhất là người duy nhất trên hành tinh tự mình tạo ra một trình biên dịch C ++ chất lượng sản xuất (phần lớn).

Cuối cùng nhưng không kém phần quan trọng, chúng tôi có tất cả các trình biên dịch độc quyền cho các vi điều khiển nhúng. IIRC, có nhiều bộ vi điều khiển được bán hàng năm hơn máy tính để bàn, thiết bị di động, máy chủ, máy trạm và CPU máy tính lớn đã được bán trong toàn bộ lịch sử điện toán kết hợp. Vì vậy, đó chắc chắn không phải là sản phẩm thích hợp.

Một đề cập danh dự được gửi tới TruffleC , một trình thông dịch C (!) Chạy trên JVM (!) Được viết bằng khung trình thông dịch Truffle AST, chậm hơn 7% so với GCC và Clang (bất kỳ tốc độ nào nhanh nhất trên bất kỳ điểm chuẩn cụ thể nào) Trò chơi Điểm chuẩn Ngôn ngữ Máy tính và nhanh hơn cả về vi điểm. Sử dụng TruffleC, nhóm Truffle đã có thể có được phiên bản JRuby + Truffle của họ để thực thi các tiện ích mở rộng Ruby C nhanh hơn so với triển khai C C thực tế!

Vì vậy, đây là 6 triển khai cùng với những triển khai mà bạn đã liệt kê mà tôi có thể đặt tên trên đỉnh đầu mà không hề biết gì về C.


1
Ngoài Microsoft Visual C, hầu hết các trình biên dịch C mà bạn đang đề cập hiếm khi được sử dụng.
Basile Starynkevitch

6
MSVC là trình biên dịch C ++ lớn, nhưng đối với C, nó khó sử dụng và bị kẹt vĩnh viễn trong C89; trình biên dịch vi điều khiển thường là mục tiêu cụ thể, bị mắc kẹt trong C89 và kỳ quặc; TruffleC dường như chưa có sẵn (nhưng thật thú vị, cảm ơn). Pathscale và Digital Mars có vẻ giống như loại phản vật chất mà tôi đang tìm kiếm.
Leushenko

8
@Mario ý tôi không phải là C89 bị hỏng, nhưng C89 không phải là hình thức cập nhật của ngôn ngữ; và điều đó có nghĩa là ít trình biên dịch được cập nhật hơn .
Leushenko

6
@Leushenko MSVC không bị kẹt vĩnh viễn trong C89. Đã có một số cuộc thảo luận và nhiều tính năng C99 nên được thêm vào. Đối với người mới bắt đầu, hầu hết thư viện C99 được hỗ trợ kể từ MSVC 2015 và một số tính năng ngôn ngữ nữa (chủ yếu là những thứ cần thiết cho C ++ 11).
Morwenn

5
@Morwenn: Chính sách của Microsoft dường như là C99 không giải quyết được vấn đề nào mà C ++ chưa giải quyết được và nếu bạn đang lập trình hệ thống, bạn nên sử dụng tập hợp con giống như C của C ++ (bất cứ điều gì không yêu cầu thời gian chạy hoặc nơi bạn không thể kiểm soát nơi trình biên dịch sẽ đặt mọi thứ - quan trọng nếu bạn cần đảm bảo rằng mã hoặc dữ liệu không được phân trang từ các trạng thái phân trang bị vô hiệu hóa). Các tính năng duy nhất từ ​​C99 sẽ là những thứ bắt buộc trong các thông số kỹ thuật C ++ sau này và những tính năng không có trí tuệ để thực hiện.
Mike Dimmick

8

Bạn cần bao nhiêu trình biên dịch?

Nếu chúng có các bộ tính năng khác nhau, bạn tạo ra một vấn đề về tính di động. Nếu chúng được hàng hóa, bạn chọn "mặc định" (GCC, Clang hoặc VS). Nếu bạn quan tâm đến hiệu suất 5% cuối cùng, bạn có điểm chuẩn.

Nếu bạn đang làm ngôn ngữ lập trình hoạt động giải trí hoặc cho mục đích nghiên cứu, thì đó có thể là ngôn ngữ hiện đại hơn. Do đó, sự phổ biến của trình biên dịch đồ chơi cho Scheme và ML. Mặc dù OCaml dường như đang nhận được một số lực kéo cho các mục đích phi học thuật phi đồ chơi.

Lưu ý điều này thay đổi rất nhiều theo ngôn ngữ. Java về cơ bản có chuỗi công cụ Sun / Oracle và GNU. Python có nhiều trình biên dịch khác nhau, không có trình biên dịch nào thực sự được tôn trọng so với trình thông dịch chuẩn. Rust và Go có chính xác một thực hiện mỗi. C # có Microsoft và Mono.


1
Rõ ràng là có nhiều lý do thú vị hơn để phát triển trình biên dịch ML ... Tôi chỉ nghĩ rằng cộng đồng C có lẽ là ba bậc lớn hơn sẽ cân bằng hiệu ứng đó. Nhưng bạn có thể đúng, 1000 * 0vẫn còn 0.
Leushenko

Tạo một trình biên dịch mới thường được liên kết với sự phân mảnh của cộng đồng (do nguyên nhân hoặc gây ra). Ví dụ, phân chia duy trì egcs vs gcc. Ngoài ra, khả năng tương thích nguồn C có xu hướng dưới 100%.
pjc50

@ pjc50: Cách viết tiêu chuẩn phân chia hiệu quả C thành một số phương ngữ rời rạc dựa trên những thứ như loại cơ bản intvà sẽ yêu cầu các trình biên dịch khác nhau diễn giải cùng một mã nguồn theo những cách rất khác nhau.
supercat

5
Tôi tin rằng, Go có hai triển khai (các 6g/ 8g/ ... toolchain và gccgo). Cũng từng có một triển khai thương mại độc quyền rất thú vị được gọi là erGo, đó là một) triển khai Windows gốc của Go tại thời điểm mà cả trình biên dịch Go không phải là trình biên dịch Go gốc hoạt động rất tốt trên Windows, b) một công ty đặt cược vào Go, lâu trước khi nó trở thành 1.0 và c) lần đầu tiên thực hiện Go được viết bằng Go (gccgo và 6g / 8g đều được viết bằng C). Tuy nhiên, cả dự án và công ty đều biến mất, trước khi họ thoát khỏi giai đoạn beta kín.
Jörg W Mittag

6

C / C ++ là duy nhất trong số các ngôn ngữ được biên dịch ở chỗ nó có 3 triển khai chính của một đặc tả chung.

Theo quy tắc loại bỏ bất cứ thứ gì không được sử dụng nhiều, mọi ngôn ngữ được biên dịch khác có từ 0 đến 1.

Và tôi nghĩ javascript là lý do duy nhất bạn cần chỉ định 'được biên dịch'.


2
Nhãn "C" được áp dụng cho một số ngôn ngữ khác nhau; một số định nghĩa mã uint16_t a=48000u; unsigned uint32_t b=(a*a)/2;là gán cho bgiá trị 8192. Một số định nghĩa mã là gán 1152000000. Hầu hết ngày nay coi nó là Hành vi không xác định và có khả năng lưu trữ 3299483648 nhưng không hứa hẹn về vấn đề đó.
supercat

1
@supercat: Ah, một điều kỳ lạ tốt với tràn quy tắc và quảng cáo số nguyên. Nó bản lề về việc sử dụng 2hoặc 2urõ ràng.
Zan Lynx

1
@ZanLynx: Tôi không nghĩ có bất kỳ trường hợp nào mà vấn đề hợp pháp 2 so với 2u ; trường hợp duy nhất tôi biết nơi có thể có vấn đề liên quan đến Hành vi không xác định với cả 2 và 2u.
supercat

3
@supercat: làm thế nào bạn có được hành vi không xác định từ /2u? Tràn không được ký được định nghĩa (như modulo 2 ^ N cho N được xác định theo thực hiện) nhưng phân chia thậm chí không thể tràn.
MSalters

2
Hành vi không xác định sẽ đến từ phép nhân các giá trị sẽ được thăng cấp thành đã ký int, nhưng sản phẩm của chúng không phù hợp với loại đó. Việc ép buộc kết quả đó thành int unsign có thể sẽ thay đổi việc giải thích giá trị kết quả, nhưng sẽ không phủ nhận Hành vi không xác định từ tính toán trước.
supercat

5

Vậy ngôn ngữ mục tiêu của bạn là gì?

Trình biên dịch SML thường nhắm mục tiêu C hoặc một cái gì đó như LLVM (hoặc như được thấy trong liên kết của bạn, JVM hoặc JavaScript).

Nếu bạn đang biên dịch C, thì không phải vì bạn đang đi đến JVM. Bạn đang đi đến một cái gì đó tồi tệ hơn C. Tệ hơn nhiều. Và sau đó bạn có thể nhân đôi địa ngục nhỏ đó một loạt lần cho tất cả các nền tảng mục tiêu của bạn.

Và chắc chắn, C không phải là C ++, nhưng tôi muốn nói rằng nó gần với C ++ hơn Scheme. Nó có tập hợp con của tội ác hành vi không xác định (Tôi đang xem kích thước của các loại được xây dựng). Và nếu bạn làm hỏng những chi tiết vụn vặt đó (hoặc thực hiện nó một cách "chính xác" nhưng không ngờ tới) thì bạn có hàng thập kỷ mã hiện có trên các hệ thống quan trọng sẽ cho bạn biết bạn khủng khiếp như thế nào. Nếu bạn làm hỏng trình biên dịch SML, nó sẽ không hoạt động - và ai đó có thể nhận thấy. Một ngày nào đó.


SML / NJ và PolyML đều đang biên dịch thành mã máy ...
Basile Starynkevitch

2
Làm thế nào là kích thước int "Hành vi không xác định"? Và tại sao UB sẽ trở thành gánh nặng cho các nhà cung cấp trình biên dịch? Gánh nặng thực sự duy nhất cho người viết trình biên dịch là độ rộng int được xác định, không phải là không xác định, vì vậy bạn phải ghi lại những gì bạn đã làm.
MSalters

@MSalters Trong thực tế, các nhà văn trình biên dịch cho một nền tảng được thiết lập có gánh nặng phù hợp với những gì người khác đi trước họ đã làm. Đôi khi điều này được ghi lại và tiêu chuẩn hóa, đôi khi không. Thật dễ dàng để tìm kích thước của một int, nhưng khó hơn để tìm thấy những gì được thực hiện với các giá trị đăng ký và nơi các đối số được lưu trữ khi gọi một hàm (có thể thay đổi tùy thuộc vào loại đối số và kiểu trả về của hàm), quy tắc bố cục cấu trúc, vv
Random832

@MSalters Hầu hết mọi người mong đợi intlà 32 hoặc 64 bit nhưng nó có thể nhỏ tới 16 bit. Không khó chút nào để tạo ra một số nằm ngoài phạm vi [−32767, +32767]inttràn là UB. Ngoài ra còn có char/ shortviệc thăng chức int hoặc unsigned int tùy thuộc vào việc intcó thể đại diện cho tất cả các giá trị của các loại gốc, mà hơn nữa có thể gây ra một sự chuyển đổi từ inttới unsigned intnếu toán hạng có kiểu khác nhau và đã chuyển đổi khác nhau, cộng với khả năng chuyển đổi khác khi bạn gán kết quả cho một biến .
Doval 19/2/2015

@MSalters Có đủ độ trễ về kích thước của các loại tiêu chuẩn và đủ chuyển đổi ngầm định mà tôi đặt cược rằng đối với bất kỳ chương trình C không tầm thường nào, có một lựa chọn kích thước số nguyên hợp pháp sẽ khiến nó làm sai hoặc gây ra không xác định hành vi.
Doval 19/2/2015
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.