Tại sao mọi người sử dụng C nếu nó rất nguy hiểm?


132

Tôi đang xem xét việc học C.

Nhưng tại sao mọi người sử dụng C (hoặc C ++) nếu nó có thể được sử dụng 'nguy hiểm'?

Nguy hiểm, ý tôi là với con trỏ và những thứ tương tự khác.

Giống như câu hỏi Stack Overflow Tại sao hàm get lại nguy hiểm đến mức không nên sử dụng? . Tại sao các lập trình viên không chỉ sử dụng Java hoặc Python hoặc ngôn ngữ được biên dịch khác như Visual Basic?


152
Tại sao các đầu bếp sử dụng dao, nếu chúng có thể được sử dụng 'nguy hiểm'?
oerkelens

78
Với sức mạnh lớn đến trách nhiệm lớn.
Pieter B

10
Joe Thổi, giáo hoàng nhiều?
Matthew James Briggs

4
Bởi vì "Back In The Day" khi C trở thành Ngôn ngữ của sự lựa chọn, chúng tôi dự kiến ​​sẽ có thể xử lý những thứ như vậy, bởi vì chúng tôi phải làm vậy. Các ngôn ngữ được giải thích hoặc mã hóa byte quá chậm vì các bộ xử lý trong ngày quá chậm. (Hôm nay tôi có thể mua một máy tính để bàn cấp thấp có CPU đa lõi 2+ GHz và bộ nhớ 4 GB từ Dell với giá 279 USD. Bạn không có IDEA nào tuyệt vời đến thế với một người như tôi với PC 4 MHz với 640 kilobyte bộ nhớ là hạnh phúc ...). Đối mặt với nó - Luật Moore đã thắng. Trò chơi. Kết thúc!
Bob Jarvis

6
@Bob Jarvis: Trò chơi chưa kết thúc. Nếu bạn nghĩ rằng PC 2 + GHz, 4GB của bạn - hoặc trong vấn đề đó, cụm vài trăm PC 4 GHz với GPU CUDA mới nhất hoặc bất cứ điều gì - đủ nhanh, bạn chỉ đơn giản là không làm việc với các vấn đề đủ khó :-)
jamesqf

Câu trả lời:


246
  1. C có trước nhiều ngôn ngữ khác mà bạn nghĩ đến. Rất nhiều điều chúng ta biết bây giờ về cách làm cho lập trình "an toàn hơn" đến từ kinh nghiệm với các ngôn ngữ như C.

  2. Nhiều ngôn ngữ an toàn hơn đã xuất hiện từ C dựa vào thời gian chạy lớn hơn, bộ tính năng phức tạp hơn và / hoặc máy ảo để đạt được mục tiêu của chúng. Kết quả là, C vẫn là một "mẫu số chung thấp nhất" trong số tất cả các ngôn ngữ phổ biến / chính thống.

    • C là một ngôn ngữ dễ thực hiện hơn vì nó tương đối nhỏ và có khả năng thực hiện đầy đủ trong cả môi trường yếu nhất, vì vậy nhiều hệ thống nhúng cần phát triển trình biên dịch riêng và các công cụ khác có khả năng cung cấp trình biên dịch chức năng cho C.

    • Vì C quá nhỏ và quá đơn giản, các ngôn ngữ lập trình khác có xu hướng giao tiếp với nhau bằng API giống như C. Đây có thể là lý do chính tại sao C sẽ không bao giờ thực sự chết, ngay cả khi hầu hết chúng ta chỉ tương tác với nó thông qua các hàm bao.

  3. Nhiều ngôn ngữ "an toàn hơn" cố gắng cải thiện C và C ++ không cố gắng trở thành "ngôn ngữ hệ thống" cho phép bạn kiểm soát gần như toàn bộ việc sử dụng bộ nhớ và hành vi thời gian chạy của chương trình. Mặc dù ngày nay, ngày càng có nhiều ứng dụng đơn giản là không cần mức độ kiểm soát đó, nhưng sẽ luôn có một số ít trường hợp cần thiết (đặc biệt là bên trong các máy ảo và trình duyệt thực hiện tất cả các ngôn ngữ an toàn, tốt đẹp này cho phần còn lại của chúng tôi).

    Ngày nay, có một vài ngôn ngữ lập trình hệ thống (Rust, Nim, D, ...) an toàn hơn C hoặc C ++. Chúng có những lợi ích của nhận thức muộn và nhận ra rằng hầu hết mọi lúc, không cần kiểm soát tốt như vậy, vì vậy hãy cung cấp giao diện chung an toàn với một vài móc / chế độ không an toàn mà người ta có thể chuyển sang khi thực sự cần thiết.

  4. Ngay cả trong C, chúng tôi đã học được rất nhiều quy tắc và hướng dẫn có xu hướng giảm đáng kể số lượng lỗi ngấm ngầm xuất hiện trong thực tế. Nhìn chung, không thể có được tiêu chuẩn để thực thi các quy tắc này một cách hồi tố bởi vì điều đó sẽ phá vỡ quá nhiều mã hiện có, nhưng thông thường sử dụng các cảnh báo trình biên dịch, linters và các công cụ phân tích tĩnh khác để phát hiện các loại vấn đề có thể phòng ngừa dễ dàng này. Tập hợp con của các chương trình C vượt qua các công cụ này với màu sắc bay đã an toàn hơn nhiều so với "chỉ C" và bất kỳ lập trình viên C có thẩm quyền nào ngày nay sẽ sử dụng một số trong số chúng.


Ngoài ra, bạn sẽ không bao giờ thực hiện một cuộc thi Java bị xáo trộn là giải trí như cuộc thi C bị xáo trộn .


7
"Mẫu số chung thấp nhất" nghe có vẻ miệt thị. Tôi muốn nói rằng, không giống như nhiều ngôn ngữ nặng hơn, C không thực thi một tấn hành lý bổ sung mà bạn không cần và cung cấp cho bạn một cơ sở nhanh như chớp để thực hiện những thứ bạn cần. Đó có phải ý của bạn?
gạch dưới

9
"Bạn không thể thực sự có cái này mà không có cái kia.": Thực sự nhiều ngôn ngữ mới (Rust, Nim, D, ...) cố gắng. Về cơ bản, điều này có nghĩa là phù hợp với một tập hợp con "an toàn" của ngôn ngữ với một vài nguyên hàm "không an toàn" khi mức độ kiểm soát này là hoàn toàn cần thiết. Tuy nhiên, tất cả những kiến ​​thức được tích lũy từ C và C ++, vì vậy có lẽ nên nói rằng tại thời điểm C và C ++ được phát triển, bạn không thể có cái này mà không có cái kia, và ngày nay có ngôn ngữ cố gắng phân vùng bit "không an toàn" của họ, nhưng họ chưa bắt kịp.
Matthieu M.

6
1) không phải là một điểm hợp lệ! C lấy các tính năng từ Algol 68, một ngôn ngữ "an toàn" theo nghĩa này; vì vậy các tác giả biết về các ngôn ngữ như vậy. Các điểm khác là tuyệt vời.
Revierpost

4
@MatthieuM. Bạn có thể muốn xem xét Microsoft Research. Họ đã sản xuất một vài HĐH được quản lý trong một hoặc hai thập kỷ qua, bao gồm một số HĐH nhanh hơn (hoàn toàn vô tình - mục tiêu chính của hầu hết các HĐH nghiên cứu này là an toàn, không phải tốc độ) so với HĐH không được quản lý tương đương đối với khối lượng công việc thực tế nhất định . Việc tăng tốc phần lớn là do các ràng buộc an toàn - kiểm tra thực thi tĩnh và động cho phép tối ưu hóa không có sẵn trong mã không được quản lý. Có khá nhiều thứ để xem xét, tất cả trong tất cả, và các nguồn được bao gồm;)
Luaan

3
@Luaan: Midori trông thật tuyệt vời; Tôi luôn mong chờ những bài viết trên blog của Joe.
Matthieu M.

41

Đầu tiên, C là một ngôn ngữ lập trình hệ thống. Vì vậy, ví dụ, nếu bạn viết một máy ảo Java hoặc trình thông dịch Python, bạn sẽ cần một ngôn ngữ lập trình hệ thống để viết chúng vào.

Thứ hai, C cung cấp hiệu suất mà các ngôn ngữ như Java và Python không có. Thông thường, tính toán hiệu năng cao trong Java và Python sẽ sử dụng các thư viện được viết bằng ngôn ngữ hiệu năng cao như C để thực hiện công việc nặng nhọc.

Thứ ba, C có dấu chân nhỏ hơn nhiều so với các ngôn ngữ như Java và Python. Điều này làm cho nó có thể sử dụng được cho các hệ thống nhúng, có thể không có tài nguyên cần thiết để hỗ trợ các môi trường thời gian chạy lớn và nhu cầu bộ nhớ của các ngôn ngữ như Java và Python.


"Ngôn ngữ lập trình hệ thống" là ngôn ngữ phù hợp để xây dựng các hệ thống sức mạnh công nghiệp với; vì chúng đứng, Java và Python không phải là ngôn ngữ lập trình hệ thống. "Chính xác những gì tạo ra một ngôn ngữ lập trình hệ thống" nằm ngoài phạm vi của câu hỏi này, nhưng một ngôn ngữ lập trình hệ thống cần phải cung cấp hỗ trợ để làm việc với nền tảng cơ bản.

Mặt khác (để phản hồi các bình luận), một ngôn ngữ lập trình hệ thống không cần phải tự lưu trữ. Vấn đề này đã đưa ra vì câu hỏi ban đầu hỏi "tại sao mọi người sử dụng C", những nhận xét đầu tiên hỏi "tại sao bạn lại cần một ngôn ngữ như C" khi bạn có PyPy, và tôi lưu ý rằng PyPy nào trong thực tế sử dụng C. Vì vậy, nó ban đầu có liên quan đến câu hỏi, nhưng thật không may (và khó hiểu) "tự lưu trữ" không thực sự liên quan đến câu trả lời này. Tôi xin lỗi tôi đã mang nó lên.

Vì vậy, để tóm tắt: Java và Python không được sử dụng cho lập trình hệ thống không phải vì các triển khai chính của chúng được diễn giải hoặc do các triển khai được biên dịch tự nhiên không phải là tự lưu trữ mà vì chúng không cung cấp hỗ trợ cần thiết để làm việc với nền tảng bên dưới.


19
"nếu bạn viết một máy ảo Java hoặc trình thông dịch Python, bạn sẽ cần một ngôn ngữ lập trình hệ thống để viết chúng vào." Ừm Làm thế nào để bạn giải thích PyPy? Tại sao bạn cần một ngôn ngữ như C để viết trình biên dịch hoặc trình thông dịch hoặc máy ảo?
Vincent Savard

10
Tôi tin rằng bạn đã tuyên bố rằng bạn cần một ngôn ngữ lập trình hệ thống để viết một máy ảo Java hoặc một trình thông dịch Python khi bạn nói "nếu bạn viết một máy ảo Java hoặc một trình thông dịch Python, bạn sẽ cần một ngôn ngữ lập trình hệ thống để viết chúng vào". Nếu PyPy không làm bạn hài lòng, bạn cũng có thể xem bất kỳ trình thông dịch hoặc trình biên dịch nào được viết bằng Haskell. Hoặc thực sự, chỉ cần thêm một tài liệu tham khảo hỗ trợ yêu cầu của bạn.
Vincent Savard

16
Ngay cả khi nó hết rùa, một thứ như PyPy không thể tồn tại nếu không có trình thông dịch Python được viết bằng một số ngôn ngữ khác.
Blrfl

18
@Birfl Nhưng điều đó không thực sự nói nhiều. C không thể được viết mà không có trình biên dịch lắp ráp và bạn không thể viết lắp ráp mà không có phần cứng thực hiện nó.
vườn

11
Nếu PyPy không phải là "ngôn ngữ lập trình hệ thống" vì trình biên dịch C có liên quan đến một nơi nào đó, thì C cũng không phải là ngôn ngữ lập trình hệ thống vì trình biên dịch được sử dụng ở đâu đó. Trên thực tế, ngày nay không phổ biến để dịch C sang một số ngôn ngữ khác? ví dụ: LLVM

30

Xin lỗi để thêm một câu trả lời khác, nhưng tôi không nghĩ bất kỳ câu trả lời hiện có nào trực tiếp giải quyết câu đầu tiên của bạn nêu rõ:

'Tôi đang cân nhắc việc học C'

Tại sao? Bạn có muốn làm những thứ mà C thường được sử dụng cho ngày hôm nay (ví dụ: trình điều khiển thiết bị, VM, công cụ trò chơi, thư viện phương tiện, hệ thống nhúng, hạt nhân OS) không?

Nếu có, thì vâng, chắc chắn học C hoặc C ++ tùy thuộc vào những người bạn quan tâm. Bạn có muốn học nó để bạn hiểu sâu hơn về ngôn ngữ cấp cao của bạn đang làm gì không?

Sau đó, bạn tiếp tục đề cập đến các mối quan tâm an toàn. Bạn không nhất thiết cần một sự hiểu biết sâu sắc về C an toàn để thực hiện điều sau, giống như cách mà một ví dụ mã trong ngôn ngữ cấp cao hơn có thể cung cấp cho bạn ý chính mà không sẵn sàng sản xuất.

Viết một số mã C để có được ý chính. Sau đó đặt nó trở lại trên kệ. Đừng quá lo lắng về sự an toàn trừ khi bạn muốn viết mã C sản xuất .


2
Công việc tuyệt vời trả lời những gì dường như là câu hỏi thực sự! Một cách tuyệt vời để đánh giá cao C / C ++ và các ngôn ngữ "an toàn hơn" cho tất cả những gì chúng thực sự là thử viết một cái gì đó giống như một công cụ cơ sở dữ liệu đơn giản. Bạn sẽ có cảm giác tốt cho từng phương pháp bạn thử và xem nơi đó dẫn bạn đến. Bạn sẽ thấy những gì cảm thấy tự nhiên, và bạn sẽ thấy nơi tiếp cận tự nhiên không thành công (ví dụ: rất dễ "xâu chuỗi" dữ liệu thô trong C - chỉ cần ghi dữ liệu!; Nhưng kết quả không khả chuyển có thể được sử dụng hạn chế). Hiểu về an toàn là khó khăn, bởi vì hầu hết các vấn đề có thể khó gặp phải.
Luaan

1
@Luaan chính xác, học cách sao chép một chuỗi bằng cách sử dụng con trỏ cho bạn ý tưởng, học cách làm như vậy một cách an toàn là một cấp độ khác, và tùy thuộc vào mục tiêu của một người có lẽ không cần thiết.
Jared Smith

2
Đây không thực sự là câu hỏi. Nhưng nó rất hữu ích cho việc mổ xẻ. Tôi quyết định làm điều đó. Tôi sẵn sàng tìm hiểu thêm về hoạt động bên trong của mọi thứ được xây dựng. Và tôi chỉ thích lập trình. Bằng cách này, tôi hy vọng hiểu được hoạt động bên trong của máy tính tốt hơn. Nó chỉ là cho vui.
Tristan

10
Tôi không đồng ý với câu cuối cùng. Học cách làm điều đó ngay trước khi phát triển những thói quen xấu.
glglgl

2
@glglgl IDK, nếu tôi đọc (hoặc viết) một đoạn mã JavaScript trên web tôi sẽ làm như vậy với sự hiểu rằng nó không sẵn sàng sản xuất: nó sẽ không có xử lý ngoại lệ, nó có thể là O (n ^ 2), v.v. điều đó là cần thiết để có được điểm. Tất cả đều cần thiết cho mã sản xuất. Tại sao điều này lại khác? Tôi có thể viết C ngây thơ cho sự chỉnh sửa của riêng mình trong khi hiểu một cách khôn ngoan rằng nếu tôi muốn đưa nó ra ngoài đó, tôi cần phải làm nhiều việc hơn nữa.
Jared Smith

14

Đây là một câu hỏi HẤP DẪN với hàng tấn câu trả lời, nhưng phiên bản ngắn là mỗi ngôn ngữ lập trình là chuyên biệt cho các tình huống khác nhau. Ví dụ: JavaScript cho web, C cho các công cụ cấp thấp, C # cho mọi thứ Windows, v.v ... Nó giúp biết bạn muốn làm gì khi bạn biết lập trình để quyết định chọn ngôn ngữ lập trình nào.

Để giải quyết điểm cuối cùng của bạn, tại sao C / C ++ qua Java / Python, nó thường đi xuống tốc độ. Tôi tạo trò chơi và Java / C # gần đây đạt tốc độ đủ tốt để trò chơi chạy. Rốt cuộc, nếu bạn muốn trò chơi của mình chạy ở tốc độ 60 khung hình mỗi giây và bạn muốn trò chơi của mình làm được nhiều việc (kết xuất đặc biệt tốn kém), thì bạn cần mã để chạy nhanh nhất có thể. Python / Java / C # / Nhiều người khác chạy trên "trình thông dịch", một lớp phần mềm bổ sung xử lý tất cả những thứ tẻ nhạt mà C / C ++ không có, chẳng hạn như quản lý bộ nhớ và bộ sưu tập rác. Chi phí hoạt động quá cao đó làm mọi thứ chậm lại, do đó, gần như mọi trò chơi lớn bạn thấy đã được thực hiện (trong 10 năm qua, dù sao đi nữa) trong C hoặc C ++. Có các trường hợp ngoại lệ: công cụ trò chơi Unity sử dụng C # * và Minecraft sử dụng Java, nhưng chúng là ngoại lệ, không phải là quy tắc. Nói chung,

* Ngay cả Unity không phải là tất cả C #, khối lượng lớn của nó là C ++ và bạn chỉ cần sử dụng C # cho mã trò chơi của mình.

EDIT Để trả lời một số ý kiến ​​xuất hiện sau khi tôi đăng bài này: Có lẽ tôi đã quá đơn giản hóa quá nhiều, tôi chỉ đưa ra bức tranh chung. Với lập trình, câu trả lời không bao giờ đơn giản. Có các thông dịch viên cho C, Javascript có thể chạy bên ngoài trình duyệt và C # có thể chạy trên mọi thứ nhờ vào Mono. Các ngôn ngữ lập trình khác nhau được chuyên biệt cho các miền khác nhau, nhưng một số lập trình viên ở đâu đó có thể tìm ra cách để có bất kỳ ngôn ngữ nào chạy trong bất kỳ ngữ cảnh nào. Vì OP dường như không biết nhiều về lập trình (giả định về phần tôi, xin lỗi nếu tôi sai), tôi đã cố gắng giữ cho câu trả lời của mình đơn giản.

Đối với các ý kiến ​​về C # gần như nhanh như C ++, từ khóa có gần như vậy. Khi tôi học đại học, chúng tôi đã đi thăm nhiều công ty trò chơi và giáo viên của tôi (người đã khuyến khích chúng tôi rời khỏi C # và vào C ++ cả năm) đã hỏi các lập trình viên ở mọi công ty, chúng tôi đã tìm hiểu lý do tại sao C ++ hơn C #, và mọi người C # nói quá chậm. Nói chung, nó chạy rất nhanh, nhưng trình thu gom rác có thể ảnh hưởng đến hiệu suất vì bạn không thể kiểm soát khi nó chạy và nó có quyền bỏ qua bạn nếu nó không muốn chạy khi bạn khuyên bạn nên chạy. Nếu bạn cần thứ gì đó để có hiệu suất cao, bạn không muốn thứ gì đó khó đoán như thế.

Để đáp ứng với nhận xét "chỉ đạt tốc độ" của tôi, vâng, phần lớn tốc độ tăng của C # đến từ phần cứng tốt hơn, nhưng khi .NET framework và trình biên dịch C # đã được cải thiện, đã có một số tăng tốc ở đó.

Về nhận xét "trò chơi được viết cùng ngôn ngữ với động cơ", tùy thuộc vào. Một số là, nhưng nhiều người được viết bằng ngôn ngữ lai. Unreal có thể làm UnrealScript và C ++, Unity thực hiện C # Javascript và Boo, nhiều công cụ khác được viết bằng C hoặc C ++ sử dụng Python hoặc Lua làm ngôn ngữ kịch bản. Không có câu trả lời đơn giản ở đó.

Và chỉ vì nó khiến tôi phải đọc "ai quan tâm nếu trò chơi của bạn chạy ở tốc độ 200fps hoặc 120fps", nếu trò chơi của bạn chạy nhanh hơn 60fps, có lẽ bạn đang lãng phí thời gian cpu, vì màn hình trung bình thậm chí không làm mới điều đó Nhanh. Một số cao cấp hơn và mới hơn làm, nhưng nó không chuẩn (chưa ...).

Và về nhận xét "bỏ qua hàng thập kỷ công nghệ", tôi vẫn ở độ tuổi 20, vì vậy khi tôi ngoại suy ngược, tôi hầu như lặp lại những gì các lập trình viên lớn tuổi và nhiều kinh nghiệm đã nói với tôi. Rõ ràng là sẽ được tranh luận trên một trang web như thế này, nhưng nó đáng để xem xét.


4
" C # cho mọi thứ Windows " - Ồ, đó là một lời ngụy biện. Và bạn thậm chí cung cấp một ví dụ. Đoàn kết. AFAIK Không được viết, nó cung cấp API C # vì ngôn ngữ này rất dễ thích nghi. Nó thực sự được thiết kế tốt. Và tôi thích c ++ hơn, nhưng tín dụng nên được đưa ra khi đến hạn. Có lẽ bạn đã trộn C # với .NET? Họ đi chơi với nhau khá thường xuyên.
luk32

2
"Ngay cả Unity không phải là tất cả C #, khối lượng lớn của nó là C ++" Và? Các trò chơi trong Unity thường sử dụng rộng rãi C # và đã xuất hiện từ khá lâu. Đề xuất rằng C # là "vừa mới đạt tốc độ" hoặc cần nhiều bối cảnh hơn, hoặc có nguy cơ bị mù với công nghệ hàng thập kỷ này.
NPSF3000

2
Gần như mọi trò chơi lớn đều được viết bằng ngôn ngữ của công cụ mà nó sử dụng: khối lượng công việc cần nhân đôi quá lớn đến nỗi không có sự cân nhắc kỹ thuật nào khác thậm chí đáng để tính đến. Kết xuất thực sự tốn kém, nhưng ngày nay tất cả được viết bằng shader và ngôn ngữ của vòng logic là không liên quan.
Peter Taylor

2
C # luôn được biên dịch JIT (không giống như Java, trong đó nhận xét của bạn là chính xác) và nó hoàn toàn có khả năng thực hiện tốc độ thực hiện rất giống với C ++ ngay từ đầu nếu bạn biết bạn đang làm gì. Đó là năm 2003 - không phải là điều tôi xem xét gần đây. Tốc độ thô không phải là vấn đề chính đối với các trò chơi (đặc biệt là với các trình tạo bóng có thể lập trình trên GPU), có những thứ khác khiến các ngôn ngữ như C # trở nên phổ biến hơn hoặc đôi khi trở nên phổ biến hơn. Hai vấn đề chính là API (vốn rất thiên về C và giao diện có thể tốn kém) và GC (chủ yếu là cho các vấn đề về độ trễ, không phải thông lượng thô).
Luaan

1
@gbjbaanb Không chỉ CPU nhanh hơn - một vấn đề lớn là C ++ và C đã có nhiều thập kỷ để hoàn thiện trình biên dịch và thời gian chạy của chúng, trong khi Java bắt đầu từ con số 0 (chủ yếu được thiết kế như một nền tảng đa nền tảng). Khi VM được cải thiện (ví dụ: việc chuyển đổi từ trình thông dịch sang trình biên dịch JIT, cải thiện GC ...), thì hiệu năng của các ứng dụng Java cũng vậy. Rất nhiều lợi thế của C / C ++ vẫn nằm ở cách tiếp cận "chúng ta hãy hy vọng không có gì phá vỡ" - tránh rất nhiều kiểm tra được coi là "không cần thiết". Nhưng nó vẫn là một con heo bộ nhớ khổng lồ - trên thực tế, những cải tiến trong việc sử dụng CPU thường có nghĩa là hiệu năng bộ nhớ kém hơn :)
Luaan

13

Thật buồn cười khi bạn khẳng định C không an toàn hơn vì "nó có con trỏ". Điều ngược lại là đúng: Java và C # thực tế chỉ có các con trỏ (đối với các loại không phải là bản địa). Lỗi phổ biến nhất trong Java có lẽ là Ngoại lệ con trỏ Null (xem https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare ). Lỗi phổ biến thứ hai có lẽ là giữ các tham chiếu ẩn đối với các đối tượng không sử dụng (ví dụ: Đối thoại đóng không được xử lý) do đó không thể được phát hành, dẫn đến các chương trình chạy dài với dấu chân bộ nhớ ngày càng tăng.

Có hai cơ chế cơ bản giúp C # và Java an toàn hơn và an toàn hơn theo hai cách khác nhau:

  • Bộ sưu tập rác làm cho chương trình ít cố gắng truy cập các đối tượng bị loại bỏ. Điều này làm cho chương trình ít có khả năng chấm dứt bất ngờ. Trái ngược với C, Java và C # theo mặc định phân bổ dữ liệu không phải là dữ liệu gốc. Điều này làm cho logic chương trình thực sự phức tạp hơn, nhưng bộ sưu tập rác tích hợp - với chi phí - chiếm phần khó.

Con trỏ thông minh gần đây của C ++ giúp công việc đó dễ dàng hơn cho các lập trình viên.

  • Java và C # biên dịch thành một mã trung gian được diễn giải / thực thi bởi thời gian chạy phức tạp. Điều này thêm một mức độ bảo mật vì thời gian chạy có thể phát hiện các hoạt động bất hợp pháp của một chương trình. Ngay cả khi chương trình được mã hóa không an toàn (có thể bằng cả hai ngôn ngữ), thời gian chạy tương ứng trong lý thuyết sẽ ngăn chặn "thoát ra" vào hệ thống.
    Thời gian chạy không bảo vệ chống lại các lỗi tràn bộ đệm, nhưng trên lý thuyết không cho phép khai thác các chương trình như vậy. Ngược lại, với C và C ++, lập trình viên phải mã hóa an toàn để tránh bị khai thác. Điều này thường không đạt được ngay lập tức nhưng cần đánh giá và lặp lại.

Điều đáng chú ý mặc dù thời gian chạy công phu cũng là một rủi ro bảo mật. Tôi thấy rằng Oracle đang cập nhật JVM vài tuần một lần vì các vấn đề an toàn mới được phát hiện. Đó là, tất nhiên, khó khăn hơn nhiều để xác minh JVM hơn một chương trình duy nhất.

Do đó, sự an toàn của thời gian chạy công phu là mơ hồ và ở mức độ lừa dối: Chương trình C trung bình của bạn có thể, với các đánh giá và lặp lại, được bảo mật một cách hợp lý. Chương trình Java trung bình của bạn chỉ an toàn như JVM; đó là, không thực sự. Không bao giờ.

Bài viết về gets()việc bạn liên kết để phản ánh các quyết định của thư viện lịch sử sẽ được thực hiện khác ngày hôm nay, không phải là ngôn ngữ cốt lõi.


3
Tôi nghĩ rằng quan điểm của tác giả ban đầu là trong C, bạn có thể thực hiện hành động không được kiểm soát đối với các con trỏ đó. Trong java, bạn nhận được một ngoại lệ đẹp ngay lập tức - trong C, bạn có thể không nhận ra mình đang đọc một vị trí không hợp lệ cho đến khi trạng thái ứng dụng của bạn bị hỏng.
Sam Dufel

1
Ngoài ra, stackoverflow.com/questions/57483/ Mạnh - sẽ chính xác hơn khi nói rằng java có "thực tế chỉ tham chiếu".
Sam Dufel

4
Tôi đã thấy tất cả các loại lỗi thú vị do các nỗ lực để tránh con trỏ rõ ràng. Thông thường vấn đề cơ bản là nhầm lẫn giữa sao chép và tham chiếu. Trong C, nếu tôi chuyển cho bạn một con trỏ tới một cái gì đó, bạn biết rằng sửa đổi nó sẽ ảnh hưởng đến bản gốc. Một số nỗ lực để tránh con trỏ làm xáo trộn sự khác biệt này, dẫn đến một mê cung của các bản sao sâu, bản sao nông và nhầm lẫn chung.
Arlie Stephens

Khẳng định rằng JVM của Oracle hút (từ quan điểm của các lỗ hổng bảo mật có thể khai thác được) và do đó, các ngôn ngữ được quản lý nói chung đưa ra nhiều lo ngại về bảo mật hơn là sử dụng ngôn ngữ được quản lý tránh giống như nói rằng Adobe Flash là một nguồn gây mất an toàn và chương trình. phát lại video và hoạt hình từ một trang web vốn phải không an toàn một cách lố bịch. Không phải tất cả các thời gian chạy của Java đều tệ như sự ghê tởm JVM của năm 1990 của Oracle / Sun và không phải tất cả các ngôn ngữ được quản lý đều là Java. (Chà, rõ ràng.)
yếu được thông báo vào

@halfinformed Vâng; Tôi đã nói rằng một chương trình chỉ an toàn như thời gian chạy của nó và chương trình "trung bình" của bạn (đọc: small-ish) có thể được thực hiện an toàn hơn bất kỳ thời gian chạy lớn nào như trình thông dịch mã byte. Câu nói đó dường như không thể phủ nhận. Việc một chương trình độc lập cụ thể hoặc thời gian chạy cụ thể có an toàn hơn hay ít hơn so với chương trình khác phụ thuộc vào độ phức tạp và thiết kế, chất lượng mã hóa và bảo trì tương ứng của chúng. Ví dụ, tôi sẽ không nói rằng sendmail an toàn hơn Java VM của Oracle; nhưng qmail có thể.
Peter A. Schneider

10

Bởi vì "an toàn" chi phí tốc độ, các ngôn ngữ "an toàn hơn" thực hiện ở tốc độ chậm hơn.

Bạn hỏi tại sao sử dụng ngôn ngữ "nguy hiểm" như C hoặc C ++, có ai đó viết cho bạn trình điều khiển video hoặc tương tự bằng Python hoặc Java, v.v. và xem bạn cảm thấy thế nào về "an toàn" :)

Nghiêm túc mà nói, bạn phải ở gần bộ nhớ lõi của máy để có thể thao tác các pixel, thanh ghi, v.v ... Java hoặc Python không thể làm điều này với bất kỳ loại tốc độ nào xứng đáng với hiệu năng ... Cả C và C ++ cho phép bạn làm điều này thông qua con trỏ và tương tự ...


20
Đó là không đúng sự thật nói chung là chi phí an toàn tăng tốc độ . Các ngôn ngữ có sẵn an toàn nhất thực hiện hầu hết các kiểm tra tại thời gian biên dịch. O'Caml, Ada, Haskell, Rust đều không bỏ xa C về tốc độ thời gian chạy trung bình. Những gì họ làm thường phải chịu là chi phí đáng kể về kích thước chương trình, hiệu quả bộ nhớ, độ trễ và thời gian biên dịch rõ ràng. Và, vâng, họ gặp khó khăn với những thứ gần gũi với kim loại. Nhưng đó không thực sự là một vấn đề tốc độ.
rẽ trái

6
Ngoài ra, C không làm những gì bạn nghĩ nó làm. C là một máy trừu tượng . Nó không cung cấp cho bạn quyền truy cập trực tiếp vào bất cứ điều gì - đó là một điều tốt. Bạn thậm chí không thể nhìn vào lắp ráp hiện đại để xem C ẩn giấu bạn bao nhiêu - lắp ráp hiện đại (ví dụ TASM) sẽ được coi là ngôn ngữ cấp cao trở lại khi C được phát triển. Tôi rất vui nếu ai đó viết trình điều khiển bằng ngôn ngữ "an toàn", cảm ơn bạn - điều đó sẽ giúp tránh được nhiều BSOD và đóng băng, không đề cập đến các lỗ hổng bảo mật :) Và quan trọng nhất là có các ngôn ngữ hệ thống an toàn hơn nhiều hơn C.
Luaan

3
@Wintermute Bạn thực sự muốn tìm kiếm Rust trước khi đưa ra nhận xét về cách các tính năng an toàn nhất thiết phải có tốc độ. Địa ngục, hệ thống cấp độ thấp của C thực sự ức chế nhiều tối ưu hóa rất hữu ích mà các trình biên dịch có thể làm khác (đặc biệt khi xem xét rằng gần như không có dự án c lớn nào có thể tránh để không vi phạm bí danh nghiêm ngặt ở đâu đó ).
Voo

7
@Wintermute Vâng, huyền thoại rằng bạn không thể tạo C / C ++ an toàn hơn mà không giới thiệu chi phí hoạt động là rất dai dẳng, đó là lý do tại sao tôi thực hiện điều này khá nghiêm trọng (có một số lĩnh vực chắc chắn là đúng [kiểm tra giới hạn]). Bây giờ tại sao Rust không phổ biến hơn? Lịch sử và sự phức tạp. Rust vẫn còn khá mới và nhiều hệ thống lớn nhất được viết bằng C đã tồn tại trước khi Rust được phát minh - bạn sẽ không viết lại một triệu LỘC bằng ngôn ngữ mới ngay cả khi nó an toàn hơn nhiều. Ngoài ra mọi lập trình viên và con chó của họ đều biết C, Rust? Chúc may mắn tìm được đủ người.
Voo

3
@Voo Chó đang làm C? ... không có gì lạ khi tôi đã thấy rất nhiều mã xấu ngoài đó ... j / k Điểm lấy về Rust (Tôi vừa tải xuống và cài đặt nó, vì vậy bạn có thể có một chuyển đổi khác để thêm) BTW liên quan để Rust làm điều đó đúng ... Tôi có thể thực hiện cùng một sự gia tăng cho "D" :)
Wintermut3

9

Bên cạnh tất cả những điều trên, còn có một trường hợp sử dụng khá phổ biến, đó là sử dụng C làm thư viện chung cho các ngôn ngữ khác.

Về cơ bản, gần như tất cả các ngôn ngữ đều có giao diện API với C.

Ví dụ đơn giản, hãy thử tạo một ứng dụng phổ biến cho Linux / IOS / Android / Windows. Bên cạnh tất cả các công cụ hiện có, cuối cùng chúng tôi đã làm một thư viện lõi trong C, và sau đó thay đổi GUI cho từng môi trường, đó là:

  • IOS: ObjectiveC có thể sử dụng thư viện C nguyên bản
  • Android: Java + JNI
  • Linux / Windows / MacOS: Với GTK / .Net, bạn có thể sử dụng các thư viện gốc. Nếu bạn sử dụng Python, Perl, Ruby thì mỗi cái đều có giao diện API gốc. (Java lại với JNI).

Theo quan điểm của tôi,


Một trong những lý do tôi thích sử dụng PHP là bởi vì hầu hết tất cả các thư viện của nó, thực sự, được viết bằng C - rất may, hoặc PHP sẽ chậm một cách khó chịu :) PHP thật tuyệt khi viết mã cẩu thả mà không sợ làm bất cứ điều gì 'nguy hiểm' (và đó là lý do tại sao tôi có xu hướng viết mã PHP nhiều hơn bất kỳ thứ gì khác - tôi thích mã cẩu thả !: D), nhưng thật tuyệt khi biết rằng bên dưới rất nhiều chức năng đó có sự tin cậy của ol Các thư viện C giúp tăng hiệu năng ;-) Ngược lại, viết mã cẩu thả trong C là một điều không nên ...
Gwyneth Llewelyn

7

Một khó khăn cơ bản với C là tên được sử dụng để mô tả một số phương ngữ có cú pháp giống hệt nhau nhưng ngữ nghĩa rất khác nhau. Một số phương ngữ an toàn hơn nhiều so với những phương ngữ khác.

Trong C như được thiết kế ban đầu bởi Dennis Ritchie, các câu lệnh C thường sẽ được ánh xạ tới các hướng dẫn máy theo kiểu có thể dự đoán được. Bởi vì C có thể chạy trên các bộ xử lý hoạt động khác nhau khi xảy ra sự cố tràn số học đã ký, một lập trình viên không biết máy sẽ hoạt động như thế nào trong trường hợp tràn số học sẽ không biết mã C chạy trên máy đó sẽ hoạt động như thế nào, nhưng nếu một máy được biết là hành xử theo một cách nhất định (ví dụ: đóng gói bổ sung của hai phần im lặng) thì việc triển khai trên máy đó thường sẽ thực hiện tương tự. Một trong những lý do khiến C nổi tiếng là nhanh là trong trường hợp lập trình viên biết rằng hành vi tự nhiên của nền tảng trong các tình huống cạnh sẽ phù hợp với nhu cầu của họ, không cần lập trình viên hoặc trình biên dịch viết mã để tạo ra các kịch bản như vậy .

Thật không may, các tác giả của trình biên dịch đã đưa ra quan điểm rằng vì Tiêu chuẩn không đặt ra yêu cầu nào về việc triển khai phải làm gì trong những trường hợp như vậy (sự lỏng lẻo nhằm cho phép các triển khai phần cứng có thể không hoạt động có thể dự đoán được), các trình biên dịch sẽ thoải mái tạo mã mà phủ nhận luật của thời gian và nhân quả.

Hãy xem xét một cái gì đó như:

int hey(int x)
{
   printf("%d", x);
   return x*10000;
}
void wow(int x)
{
  if (x < 1000000)
    printf("QUACK!");
  hey(x);    
}

Lý thuyết trình biên dịch siêu hiện đại (nhưng thời thượng) sẽ đề xuất rằng trình biên dịch sẽ xuất ra "QUACK!" vô điều kiện, vì trong mọi trường hợp điều kiện sai, chương trình sẽ kết thúc việc gọi hành vi không xác định thực hiện một bội số mà kết quả sẽ bị bỏ qua. Vì Standard sẽ cho phép trình biên dịch làm bất cứ điều gì nó thích trong trường hợp như vậy, nên nó cho phép trình biên dịch xuất ra "QUACK!".

Trong khi C từng an toàn hơn ngôn ngữ lắp ráp, khi sử dụng trình biên dịch siêu hiện đại thì điều ngược lại là đúng. Trong ngôn ngữ lắp ráp, tràn số nguyên có thể khiến phép tính mang lại kết quả vô nghĩa, nhưng trên hầu hết các nền tảng sẽ là phạm vi ảnh hưởng của nó. Nếu kết quả cuối cùng bị bỏ qua, thì tràn sẽ không thành vấn đề. Tuy nhiên, trong C siêu hiện đại, ngay cả những dạng thông thường là "lành tính" của Hành vi không xác định (chẳng hạn như tràn số nguyên trong một phép tính kết thúc bị bỏ qua) có thể gây ra việc thực hiện chương trình tùy ý.


1
ngay cả trong một trình biên dịch siêu hiện đại, C không giới hạn - kiểm tra các mảng. nếu nó làm như vậy, điều đó sẽ không tương thích với định nghĩa của ngôn ngữ. đôi khi tôi sử dụng thực tế đó để tạo các mảng với một con trỏ bổ sung vào giữa mảng để có các chỉ số âm.
robert bristow-johnson

1
Tôi muốn xem bằng chứng về ví dụ của bạn tạo ra "QUACK!" vô điều kiện. x chắc chắn thể lớn hơn 1000000 tại điểm so sánh, và việc đánh giá sau này sẽ dẫn đến tràn không ngăn cản điều đó. Hơn nữa, nếu bạn đã kích hoạt nội tuyến cho phép loại bỏ bội số tràn, đối số của bạn về các hạn chế phạm vi ngầm sẽ không được giữ.
Graham

2
@ robertbristow-johnson: Trên thực tế, Tiêu chuẩn khá rõ ràng nói rằng int arr[5][[5], ví dụ , một nỗ lực truy cập arr[0][5]sẽ mang lại Hành vi không xác định. Quy tắc như vậy làm cho trình biên dịch được đưa ra một cái gì đó giống như arr[1][0]=3; arr[0][i]=6; arr[1][0]++;suy ra arr[1][0]sẽ bằng 4, mà không cần quan tâm đến giá trị của i.
supercat

2
@ robertbristow-johnson: Ngay cả khi trình biên dịch phân bổ các mảng trong một cấu trúc tuần tự mà không có khoảng trống, điều đó không đảm bảo rằng việc lập chỉ mục một trong các mảng được đảm bảo ảnh hưởng đến mảng khác. Xem godbolt.org/g/Avt3KW để biết ví dụ về cách gcc sẽ xử lý mã đó.
supercat

1
@ robertbristow-johnson: Tôi đã nhận xét hội nghị để giải thích những gì nó đang làm. Trình biên dịch thấy rằng mã lưu trữ 1 vào s-> Array2 [0] và sau đó tăng s-> Array2 [0], vì vậy gcc kết hợp hai thao tác đó bằng cách lưu mã đơn giản vào giá trị 2, mà không xem xét khả năng ghi can thiệp đến s-> Array1 [i] có thể ảnh hưởng đến giá trị của s-> Array1 [0] (vì theo Tiêu chuẩn, nó không thể).
supercat

5

Lý do lịch sử. Tôi không thường xuyên viết mã hoàn toàn mới, chủ yếu là tôi có thể duy trì và mở rộng những thứ cũ đã chạy trong nhiều thập kỷ. Tôi chỉ vui vì nó là C chứ không phải Fortran.

Tôi có thể bị kích thích khi một số sinh viên nói, "nhưng tại sao bạn lại làm điều X tồi tệ này khi bạn có thể làm Y?". Chà, X là công việc tôi đã có và nó trả các hóa đơn rất độc đáo. Tôi đã làm Y trong một dịp, và nó rất vui, nhưng X là điều mà hầu hết chúng ta làm.


5

"Nguy hiểm" là gì?

Khiếu nại rằng C là "nguy hiểm" là một điểm thường xuyên nói trong các cuộc chiến ngọn lửa ngôn ngữ (thường xuyên nhất so với Java). Tuy nhiên, bằng chứng cho tuyên bố này là không rõ ràng.

C là một ngôn ngữ với một bộ tính năng cụ thể. Một số tính năng này có thể cho phép một số loại lỗi nhất định mà các loại ngôn ngữ khác không cho phép (nguy cơ quản lý bộ nhớ của C thường được tô sáng). Tuy nhiên, điều này không giống với lập luận rằng C nguy hiểm hơn các ngôn ngữ khác nói chung . Tôi không biết bất cứ ai cung cấp bằng chứng thuyết phục về điểm này.

Ngoài ra, "nguy hiểm" phụ thuộc vào ngữ cảnh: bạn đang cố gắng làm gì và bạn lo lắng về những rủi ro nào?

Trong nhiều bối cảnh tôi sẽ coi C "nguy hiểm" hơn ngôn ngữ cấp cao, bởi vì nó đòi hỏi bạn phải thực hiện thủ công hơn các chức năng cơ bản, làm tăng nguy cơ lỗi. Ví dụ, thực hiện một số xử lý văn bản cơ bản hoặc phát triển trang web trong C thường sẽ bị câm, bởi vì các ngôn ngữ khác có các tính năng giúp việc này dễ dàng hơn nhiều.

Tuy nhiên, C và C ++ được sử dụng rộng rãi cho các hệ thống quan trọng, bởi vì một ngôn ngữ nhỏ hơn với sự kiểm soát trực tiếp hơn về độ cứng được coi là "an toàn hơn" trong bối cảnh đó. Từ một câu trả lời Stack Overflow rất tốt :

Mặc dù C và C ++ không được thiết kế riêng cho loại ứng dụng này, nhưng chúng được sử dụng rộng rãi cho phần mềm nhúng và an toàn quan trọng vì nhiều lý do. Các thuộc tính chính của ghi chú là kiểm soát quản lý bộ nhớ (cho phép bạn tránh phải thu gom rác chẳng hạn), các thư viện thời gian chạy lõi đơn giản, được gỡ lỗi tốt và hỗ trợ công cụ trưởng thành. Rất nhiều chuỗi công cụ phát triển nhúng được sử dụng ngày nay được phát triển lần đầu tiên vào những năm 1980 và 1990 khi đây là công nghệ hiện tại và xuất phát từ văn hóa Unix đang thịnh hành vào thời điểm đó, vì vậy những công cụ này vẫn phổ biến cho loại công việc này.

Mặc dù mã quản lý bộ nhớ thủ công phải được kiểm tra cẩn thận để tránh lỗi, nhưng nó cho phép mức độ kiểm soát thời gian phản hồi của ứng dụng không khả dụng với các ngôn ngữ phụ thuộc vào bộ sưu tập rác. Các thư viện thời gian chạy cốt lõi của ngôn ngữ C và C ++ tương đối đơn giản, trưởng thành và được hiểu rõ, vì vậy chúng là một trong những nền tảng ổn định nhất hiện có.


2
Tôi muốn nói C siêu hiện đại cũng nguy hiểm hơn ngôn ngữ lắp ráp hoặc các phương ngữ cấp thấp chính hãng của C, luôn hoạt động như thể chúng luôn chuyển các hoạt động của C thành các hoạt động mã máy mà không cần quan tâm đến các trường hợp cạnh trong đó các hoạt động mã máy tự nhiên sẽ đã xác định hành vi nhưng Tiêu chuẩn C sẽ không áp đặt yêu cầu. Cách tiếp cận siêu hiện đại trong đó một tràn số nguyên có thể phủ nhận các quy tắc về thời gian và quan hệ nhân quả dường như ít có khả năng tạo ra mã an toàn.
supercat

5

Để thêm vào các câu trả lời hiện có, tất cả đều tốt và nói rằng bạn sẽ chọn Python hoặc PHP cho dự án của mình, vì tính an toàn tương đối của chúng. Nhưng ai đó phải thực hiện những ngôn ngữ đó và, khi họ làm, có lẽ họ sẽ thực hiện nó trong C. (Hoặc, tốt, một cái gì đó giống như vậy.)

Vì vậy, đó là lý do tại sao mọi người sử dụng C - để tạo ra các công cụ ít nguy hiểm hơn mà bạn muốn sử dụng.


2

Cho phép tôi viết lại câu hỏi của bạn:

Tôi đang xem xét việc học [công cụ].

Nhưng tại sao mọi người sử dụng [công cụ] (hoặc [công cụ liên quan]) nếu [họ] có thể được sử dụng 'nguy hiểm'?

Bất kỳ công cụ thú vị nào cũng có thể được sử dụng một cách nguy hiểm, bao gồm cả ngôn ngữ lập trình. Bạn tìm hiểu thêm để bạn có thể làm nhiều hơn (và do đó ít nguy hiểm hơn được tạo ra khi bạn sử dụng công cụ). Cụ thể, bạn tìm hiểu công cụ để bạn có thể làm điều mà công cụ đó phù hợp (và có thể nhận ra khi nào công cụ đó là công cụ tốt nhất trong số các công cụ bạn biết).

Ví dụ, nếu bạn cần đặt một lỗ hình trụ có đường kính 6 mm, sâu 5 cm trong một khối gỗ, máy khoan là một công cụ tốt hơn nhiều so với trình phân tích cú pháp LALR. Nếu bạn biết hai công cụ này là gì, bạn sẽ biết công cụ nào phù hợp. Nếu bạn đã biết cách sử dụng máy khoan, thì đấy!

C chỉ là một công cụ khác. Nó tốt hơn cho một số nhiệm vụ so với những nhiệm vụ khác. Các câu trả lời khác ở đây giải quyết điều này. Nếu bạn học một số C, bạn sẽ nhận ra khi nào nó là công cụ phù hợp và khi nào thì không.


Câu trả lời này là lý do tại sao các câu hỏi được đưa ra dưới dạng "chủ yếu dựa trên quan điểm". Đừng nói rằng C có lợi thế của nó, hãy nói chúng là gì!
Revierpost

1

Tôi đang xem xét việc học C

Không có lý do cụ thể để không học C nhưng tôi sẽ đề xuất C ++. Nó cung cấp phần lớn những gì C làm (vì C ++ là một bộ siêu C), với một lượng lớn "bổ sung". Học C trước C ++ là không cần thiết - chúng là những ngôn ngữ riêng biệt hiệu quả.

Nói cách khác, nếu C là một bộ công cụ chế biến gỗ, thì đó có thể là:

  • cây búa
  • móng tay
  • cưa tay
  • khoan tay
  • khối sander
  • đục (có thể)

Bạn có thể xây dựng bất cứ thứ gì với những công cụ này - nhưng bất cứ điều gì tốt đẹp có khả năng đòi hỏi nhiều thời gian và kỹ năng.

C ++ là tập hợp các công cụ điện tại cửa hàng phần cứng địa phương của bạn.

Nếu bạn gắn bó với các tính năng ngôn ngữ cơ bản để bắt đầu, C ++ có đường cong học tập bổ sung tương đối ít.

Nhưng tại sao mọi người sử dụng C (hoặc C ++) nếu nó có thể được sử dụng 'nguy hiểm'?

Bởi vì một số người không muốn đồ nội thất từ ​​IKEA. =)

Nghiêm túc mà nói, mặc dù nhiều ngôn ngữ "cao hơn" C hoặc C ++ có thể có những thứ khiến chúng (có khả năng) "dễ sử dụng" hơn trong một số khía cạnh nhất định, nhưng điều này không phải lúc nào cũng tốt. Nếu bạn không thích cách làm một cái gì đó hoặc một tính năng không được cung cấp, có thể bạn sẽ không thể làm được gì nhiều về nó. Mặt khác, C và C ++ cung cấp đủ các tính năng ngôn ngữ "cấp thấp" (bao gồm cả con trỏ) để bạn có thể truy cập nhiều thứ khá trực tiếp (đặc biệt là phần cứng hoặc hệ điều hành) hoặc tự xây dựng nó, điều này có thể không thể thực hiện được ngôn ngữ như được thực hiện.

Cụ thể hơn, C có bộ tính năng sau đây khiến nhiều lập trình viên mong muốn:

  • Tốc độ - Do tính đơn giản tương đối và tối ưu hóa trình biên dịch qua nhiều năm, nên nó thực sự rất nhanh. Ngoài ra, rất nhiều người đã tìm ra rất nhiều phím tắt cho các mục tiêu cụ thể khi sử dụng ngôn ngữ, điều này khiến nó có khả năng nhanh hơn nữa.
  • Kích thước - Vì những lý do tương tự như tốc độ được liệt kê cho tốc độ, các chương trình C có thể được thực hiện rất nhỏ (cả về kích thước thực thi và mức sử dụng bộ nhớ), điều này mong muốn đối với các môi trường có bộ nhớ hạn chế (ví dụ như nhúng hoặc di động).
  • Khả năng tương thích - C đã xuất hiện từ lâu và mọi người đều có công cụ và thư viện cho nó. Bản thân ngôn ngữ cũng không kén chọn - nó hy vọng bộ xử lý sẽ thực thi các lệnh và bộ nhớ để chứa nội dung và đó là về nó.

    Hơn nữa, có một cái gì đó được gọi là Giao diện nhị phân ứng dụng (ABI) . Nói tóm lại, đây là một cách để các chương trình giao tiếp ở cấp mã máy, có thể có lợi thế so với Giao diện lập trình ứng dụng (API) . Mặc dù các ngôn ngữ khác như C ++ có thể có ABI, thông thường những ngôn ngữ này ít đồng nhất (đã thỏa thuận) hơn C, vì vậy C tạo ra ngôn ngữ nền tảng tốt khi bạn muốn sử dụng ABI để giao tiếp với một chương trình khác vì một số lý do.

Tại sao các lập trình viên không chỉ sử dụng Java hoặc Python hoặc ngôn ngữ được biên dịch khác như Visual Basic?

Hiệu quả (và đôi khi các chương trình quản lý bộ nhớ không thể thực hiện được nếu không truy cập tương đối trực tiếp vào bộ nhớ).

Truy cập trực tiếp vào bộ nhớ bằng các con trỏ giới thiệu rất nhiều thủ thuật gọn gàng (thường là nhanh chóng) khi bạn có thể đặt bàn chân mập mạp của mình lên các khối nhỏ và số không trong khối lập phương bộ nhớ của bạn và không phải đợi giáo viên ol 'chỉ đưa ra đồ chơi tại thời gian chơi sau đó múc chúng lên một lần nữa.

Nói tóm lại, việc thêm các công cụ có khả năng tạo ra độ trễ hoặc giới thiệu sự phức tạp không mong muốn.

Về ngôn ngữ kịch bản và ilk đó, bạn phải nỗ lực để có được các ngôn ngữ yêu cầu các chương trình thứ cấp chạy hiệu quả như C (hoặc bất kỳ ngôn ngữ được biên dịch nào) thực sự. Việc thêm một trình thông dịch nhanh chóng vốn đã giới thiệu khả năng giảm tốc độ thực thi và tăng mức sử dụng bộ nhớ vì bạn đang thêm một chương trình khác vào hỗn hợp. Hiệu quả chương trình của bạn phụ thuộc nhiều vào hiệu quả của chương trình thứ cấp này cũng như mức độ (kém =)) bạn đã viết mã chương trình ban đầu của mình. Chưa kể chương trình của bạn thường hoàn toàn phụ thuộc vào chương trình thứ hai để thậm chí thực thi. Chương trình thứ hai đó không tồn tại vì một số lý do trên một hệ thống cụ thể? Mã không đi.

Trong thực tế, việc giới thiệu bất cứ thứ gì "thêm" có khả năng làm chậm hoặc làm phức tạp mã của bạn. Trong các ngôn ngữ "không có con trỏ đáng sợ", bạn luôn chờ đợi các đoạn mã khác dọn dẹp phía sau bạn hoặc tìm ra cách "an toàn" để thực hiện - bởi vì chương trình của bạn vẫn đang thực hiện các hoạt động truy cập bộ nhớ giống như có thể được thực hiện với con trỏ. Bạn không phải là người xử lý nó (vì vậy bạn không thể f * ck nó lên, thiên tài = P).

Nguy hiểm, ý tôi là với con trỏ và những thứ tương tự khác. [...] Giống như câu hỏi Stack Overflow Tại sao hàm get lại nguy hiểm đến mức không nên sử dụng?

Theo câu trả lời được chấp nhận:

"Nó vẫn là một phần chính thức của ngôn ngữ theo tiêu chuẩn ISO C năm 1999, nhưng nó đã bị xóa chính thức bởi tiêu chuẩn năm 2011. Hầu hết các triển khai C vẫn hỗ trợ nó, nhưng ít nhất gcc đưa ra cảnh báo cho bất kỳ mã nào sử dụng nó."

Quan niệm rằng bởi vì một cái gì đó có thể được thực hiện bằng một ngôn ngữ, nó phải được thực hiện là ngớ ngẩn. Ngôn ngữ có sai sót được sửa chữa. Vì lý do tương thích với mã cũ hơn, cấu trúc này vẫn có thể được sử dụng. Nhưng không có gì (có khả năng) buộc một lập trình viên sử dụng get () và trên thực tế, lệnh này về cơ bản được thay thế bằng các lựa chọn thay thế an toàn hơn.

Hơn nữa, vấn đề với got () không phải là vấn đề con trỏ mỗi se. Đó là một vấn đề với một lệnh không nhất thiết phải biết cách sử dụng bộ nhớ một cách an toàn. Theo một nghĩa trừu tượng, đây là tất cả các vấn đề về con trỏ - đọc và viết những thứ bạn không cần phải làm. Đó không phải là vấn đề với con trỏ; đó là một vấn đề với việc thực hiện con trỏ.

Để làm rõ, con trỏ không nguy hiểm cho đến khi bạn vô tình truy cập vào một vị trí bộ nhớ mà bạn không có ý định. Và thậm chí sau đó không đảm bảo máy tính của bạn sẽ tan chảy hoặc phát nổ. Trong hầu hết các trường hợp, chương trình của bạn sẽ ngừng hoạt động (chính xác).

Điều đó nói rằng, bởi vì các con trỏ cung cấp quyền truy cập vào các vị trí bộ nhớ và vì dữ liệu và mã thực thi tồn tại trong bộ nhớ cùng nhau, có đủ nguy cơ thực sự của tham nhũng vô tình mà bạn muốn quản lý bộ nhớ chính xác.

Đến thời điểm đó, bởi vì các hoạt động truy cập bộ nhớ trực tiếp thực sự thường mang lại ít lợi ích nói chung hơn so với những năm trước đây, ngay cả các ngôn ngữ được thu thập rác như C ++ đã giới thiệu những thứ như con trỏ thông minh để giúp thu hẹp khoảng cách giữa hiệu quả và an toàn bộ nhớ.

Tóm lại, có rất ít lý do để sợ con trỏ miễn là nó được sử dụng an toàn. Chỉ cần lấy một gợi ý từ phiên bản Steve "The Hunter Hunter" của South Park - đừng đi xung quanh dính ngón tay cái của bạn vào lỗ hổng của crocs .


2
Tôi không đồng ý với gợi ý học C ++ thay vì C. Viết C ++ tốt hơn viết C tốt và đọc C ++ khó hơn đọc C. Vì vậy, đường cong học tập của C ++ dốc hơn nhiều. "C ++ là một bộ siêu C" Điều này ít nhiều giống như nói rằng giày cao cổ là một đôi dép lê. Chúng có những ưu điểm và cách sử dụng khác nhau và mỗi cái đều có những tính năng mà cái kia không có.
martinkunev

"Viết C ++ tốt khó hơn viết C tốt" - Hoàn toàn đúng. =) "[R] ead C ++ khó hơn đọc C" - Bất kỳ chương trình nâng cao nào cũng không thể phân biệt được với ma thuật ;-) Hai xu của tôi là điều này phụ thuộc nhiều vào lập trình viên hơn phụ thuộc vào ngôn ngữ, mặc dù C ++ không giúp được gì nhiều cho chính nó trong thể loại này. "Vì vậy, đường cong học tập của C ++ dốc hơn nhiều." - Về lâu dài, vâng. Trong ngắn hạn, ít hơn (ý kiến ​​của tôi). Thông thường, hầu hết các khóa học ngôn ngữ cơ bản trong C và C ++ có khả năng bao gồm các loại tài liệu chung giống nhau, ngoại trừ các lớp cho C ++.
Anaksunaman

2
"Chúng có những lợi thế và cách sử dụng khác nhau và mỗi cái đều có những tính năng mà cái kia không có." - Như đã đề cập "Không có lý do cụ thể để không học C [.]" C là một ngôn ngữ tốt và tôi kiên định với điều đó. Nếu nó phù hợp với OP hoặc bất cứ ai khác, tôi hoàn toàn hỗ trợ việc học nó. =)
Anaksunaman

Học C dạy cho bạn cách máy hoạt động (không phải là tất cả, nhưng vẫn là một bước gần hơn với kim loại). Đó là một lý do rất tốt để học nó.
Đặc vụ_L

1

Như mọi khi, ngôn ngữ lập trình chỉ là hệ quả của việc giải quyết vấn đề. Trong thực tế, bạn nên học không chỉ C mà nhiều ngôn ngữ khác nhau (và các cách lập trình máy tính khác, có thể là công cụ GUI hoặc trình thông dịch lệnh) để có một hộp công cụ hợp lý để sử dụng khi giải quyết vấn đề.

Đôi khi bạn sẽ thấy rằng một vấn đề cho vay chính nó đối với một cái gì đó được bao gồm trong các thư viện mặc định của Java, trong trường hợp như vậy bạn có thể chọn Java để tận dụng điều đó. Trong các trường hợp khác, có thể bạn cần phải làm một cái gì đó trên Windows đơn giản hơn rất nhiều trong thời gian chạy .NET, vì vậy bạn có thể sử dụng C # hoặc VB. Có thể có một công cụ đồ họa hoặc tập lệnh để giải quyết vấn đề của bạn, sau đó bạn có thể sử dụng chúng. Có thể bạn cần viết một ứng dụng GUI trên nhiều nền tảng, Java có thể là một tùy chọn, được cung cấp các thư viện đi kèm trong JDK, nhưng một lần nữa, một nền tảng đích có thể thiếu JRE nên có thể bạn thay vào đó chọn C và SDL (hoặc tương tự).

C có một vị trí quan trọng trong bộ công cụ này, vì nó là chung, nhỏ và nhanh và cũng được biên dịch thành machinecode. Nó cũng được hỗ trợ trên mọi nền tảng dưới ánh mặt trời (tuy nhiên không phải không biên dịch lại).

Điểm mấu chốt là, bạn nên học càng nhiều công cụ, ngôn ngữ và mô hình càng tốt.

Hãy tránh xa suy nghĩ: "Tôi là một lập trình viên X" (X = C, C ++, Java, v.v.)

Chỉ cần sử dụng "Tôi là một lập trình viên".

Một lập trình viên giải quyết các vấn đề và thiết kế các thuật toán bằng cách hướng dẫn các máy thực hiện khối lượng công việc. Kết thúc câu chuyện. Điều này không liên quan đến ngôn ngữ. Kỹ năng quan trọng nhất của bạn là giải quyết vấn đề và phân tích logic các vấn đề có cấu trúc, kỹ năng / lựa chọn ngôn ngữ là LUÔN LUÔN và / hoặc hậu quả của bản chất của vấn đề.

Một con đường thú vị nếu bạn quan tâm đến C là mở rộng bộ kỹ năng của bạn với Go. Go thực sự là một C cải tiến, với bộ sưu tập và giao diện rác, cũng như một mô hình / kênh phân luồng được xây dựng đẹp mắt, cũng mang lại nhiều lợi ích của C (như số học con trỏ và biên dịch mã máy).


0

Nó phụ thuộc vào những gì bạn định làm với nó. C được thiết kế để thay thế cho ngôn ngữ lắp ráp và là ngôn ngữ cấp cao gần với ngôn ngữ máy nhất. Do đó, nó có chi phí thấp về kích thước và hiệu suất và phù hợp cho lập trình hệ thống và các tác vụ khác đòi hỏi một dấu chân nhỏ và tiến gần đến phần cứng bên dưới.


0

Khi bạn làm việc ở mức bit và byte, bộ nhớ là bộ sưu tập dữ liệu đồng nhất thô, thường sẽ được yêu cầu để thực hiện hiệu quả các công cụ cấp phát và cấu trúc dữ liệu hiệu quả nhất, không có sự an toàn nào. An toàn chủ yếu là một khái niệm liên quan đến loại dữ liệu mạnh và bộ cấp phát bộ nhớ không hoạt động với các loại dữ liệu. Nó hoạt động với các bit và byte để kết hợp với các bit và byte tương tự có khả năng đại diện cho một loại dữ liệu một thời điểm và sau đó.

Không có vấn đề gì nếu bạn sử dụng C ++ trong trường hợp đó. Bạn vẫn đang rắc static_castskhắp mã để truyền từ void*con trỏ và vẫn làm việc với bit và byte và chỉ xử lý nhiều rắc rối liên quan đến việc tôn trọng hệ thống loại trong ngữ cảnh này so với C có hệ thống loại đơn giản hơn nhiều khi bạn rảnh đến memcpycác bit và byte xung quanh mà không lo lắng về việc ủi trên hệ thống loại.

Trên thực tế, việc làm việc trong C ++ thường khó hơn, một ngôn ngữ an toàn tổng thể hơn, trong bối cảnh bit và byte ở mức độ thấp như vậy mà không cần viết mã nguy hiểm hơn so với trong C, vì bạn có thể ủi trên hệ thống loại của C ++ và làm những việc như ghi đè vptrs và không gọi được các hàm tạo và hàm hủy sao chép vào thời điểm thích hợp. Nếu bạn dành thời gian thích hợp để tôn trọng các loại này và sử dụng vị trí mới và gọi thủ công, v.v., thì bạn sẽ tiếp xúc với thế giới xử lý ngoại lệ trong bối cảnh quá thấp để RAII trở nên thiết thực và đạt được ngoại lệ- an toàn trong bối cảnh cấp thấp như vậy là rất khó (bạn phải giả vờ như bất kỳ chức năng nào có thể ném và nắm bắt mọi khả năng và đẩy lùi mọi tác dụng phụ như một giao dịch không thể chia sẻ như không có gì xảy ra). Mã C thường có thể "

Và không thể thực hiện các cấp phát như vậy bằng các ngôn ngữ không cho phép bạn gặp "nguy hiểm" ở đây; bạn phải dựa vào bất kỳ công cụ phân bổ nào mà họ cung cấp (được triển khai nhiều nhất trong C hoặc C ++) và hy vọng nó đủ tốt cho mục đích của bạn. Và hầu như luôn luôn hiệu quả hơn nhưng phân bổ chung và cấu trúc dữ liệu ít phù hợp hơn cho các mục đích cụ thể của bạn nhưng áp dụng hẹp hơn nhiều vì chúng được thiết kế riêng cho mục đích của bạn.

Hầu hết mọi người không cần C hay C ++ vì họ chỉ có thể gọi mã được triển khai ban đầu trong C hoặc C ++ hoặc thậm chí có thể lắp ráp đã được triển khai cho họ. Nhiều người có thể hưởng lợi từ việc đổi mới ở cấp độ cao, như xâu chuỗi một chương trình hình ảnh chỉ sử dụng các thư viện của các chức năng xử lý hình ảnh hiện có đã được triển khai trong C khi họ không đổi mới quá nhiều ở mức thấp nhất qua các pixel riêng lẻ, nhưng có thể cung cấp một giao diện người dùng rất thân thiện và quy trình làm việc chưa từng thấy trước đây. Trong trường hợp đó, nếu mục đích của phần mềm chỉ là thực hiện các cuộc gọi cấp cao vào các thư viện cấp thấp ( "xử lý toàn bộ hình ảnh này cho tôi, không phải cho từng pixel, hãy làm gì đó" ), thì có thể cho rằng đó là tối ưu hóa sớm thậm chí cố gắng bắt đầu viết một ứng dụng như vậy trong C.

Nhưng nếu bạn đang làm một cái gì đó mới ở mức thấp, nơi nó giúp truy cập dữ liệu ở mức độ thấp như bộ lọc hình ảnh hoàn toàn mới chưa từng thấy trước đó đủ nhanh để hoạt động trên video HD trong thời gian thực, thì bạn thường phải nhận một chút nguy hiểm.

Thật dễ dàng để có được những thứ này cho phép. Tôi nhớ một bài đăng trên facebook với ai đó chỉ ra cách khả thi để tạo một trò chơi video 3D bằng Python với ngụ ý rằng các ngôn ngữ cấp thấp đang trở nên lỗi thời và chắc chắn đây là một trò chơi đẹp mắt. Nhưng Python đã thực hiện các cuộc gọi cấp cao vào các thư viện được triển khai trong C để thực hiện tất cả các công việc nặng nhọc. Bạn không thể tạo Unreal Engine 4 bằng cách thực hiện các cuộc gọi cấp cao vào các thư viện hiện có. Động cơ không thực 4thư viện. Nó đã làm tất cả mọi thứ chưa từng tồn tại trong các thư viện và động cơ khác từ ánh sáng đến hệ thống kế hoạch chi tiết nút và cách nó có thể biên dịch và chạy mã khi đang di chuyển. Nếu bạn muốn đổi mới ở mức độ động cơ / lõi / nhân thấp, thì bạn phải đạt cấp độ thấp. Nếu tất cả các nhà phát triển trò chơi chuyển sang ngôn ngữ an toàn cấp cao, sẽ không có Unreal Engine 5, hoặc 6 hoặc 7. Có thể mọi người vẫn sử dụng Unreal Engine 4 thập kỷ sau vì bạn không thể đổi mới ở cấp độ bắt buộc với một động cơ thế hệ tiếp theo bằng cách thực hiện các cuộc gọi cấp cao vào cuộc gọi cũ.

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.