Tôi tin rằng C là một ngôn ngữ tốt để tìm hiểu các nguyên tắc đằng sau lập trình. Bạn sẽ học được gì trong các ngôn ngữ cấp thấp bị "phù phép" khỏi các ngôn ngữ cấp cao, chẳng hạn như Ruby?
Tôi tin rằng C là một ngôn ngữ tốt để tìm hiểu các nguyên tắc đằng sau lập trình. Bạn sẽ học được gì trong các ngôn ngữ cấp thấp bị "phù phép" khỏi các ngôn ngữ cấp cao, chẳng hạn như Ruby?
Câu trả lời:
Không có nguyên tắc, theo nghĩa trừu tượng chung của khoa học máy tính, hiện diện trong C mà cũng không có trong các ngôn ngữ cấp cao hơn. Tất cả các khoa học máy tính tập trung vào các thuật toán và tất cả các thuật toán có thể được thực hiện bằng bất kỳ ngôn ngữ nào là Turing-Complete như C là.
Sự khác biệt mà C mang theo ngoài các ngôn ngữ cấp cao hơn tương tự như sự khác biệt mà mã máy mang theo ngoài C: Mối quan hệ của máy với mã.
Khi bạn viết mã bằng các ngôn ngữ cấp cao, bạn thường không quan tâm đến việc mã của bạn tương tác với máy như thế nào. Máy ảo mà ngôn ngữ tự xác định ẩn chứa nhiều khía cạnh của việc thực thi mã.
Trong C, sự tương tác của chương trình với bộ nhớ của bạn được đặt lên hàng đầu. Không chỉ đơn thuần là bạn phải quản lý việc sử dụng heap, nó bao gồm sự tương tác của mã với ngăn xếp và cách truy cập bộ nhớ đơn thuần của mã ảnh hưởng đến hành vi và hiệu suất của mã của bạn - thậm chí không theo thứ tự truy cập bộ nhớ có thể được phép thoát khỏi sự chú ý của bạn, vì đọc sai bộ nhớ không đúng lúc có thể làm tê liệt hiệu quả.
Trong các ngôn ngữ cấp cao hơn, những điều này chỉ đơn giản là không rõ ràng. Bộ nhớ được phân bổ và giải quyết mà không có kiến thức của bạn, và đôi khi không có sự nhắc nhở của bạn. Thông thường, điều này chỉ đơn giản là ngoài tầm kiểm soát của bạn. Thời gian, ở đâu, như thế nào và tại sao của hầu hết các phân bổ bộ nhớ chỉ đơn giản là ẩn khỏi bạn.
Tương tự như vậy, theo một hướng khác, viết mã máy hoặc mã lắp ráp mang lại nhiều chi tiết hơn cho tiền cảnh: Hầu như không có gì còn lại ngoài tầm nhìn của bạn và mã của bạn phải được ghi nhận về mọi phân bổ, mọi tài nguyên, mọi phần dữ liệu đi qua thông qua các thanh ghi của CPU - kiến thức đã bị loại bỏ khỏi các ngôn ngữ cấp cao như là phức tạp.
Tôi biết C là một ngôn ngữ tốt để tìm hiểu các nguyên tắc đằng sau lập trình.
Tôi không đồng ý. C vắng mặt quá nhiều tính năng để học các nguyên tắc đằng sau lập trình. Các tính năng của C để tạo ra sự trừu tượng là rất tệ và sự trừu tượng là một trong những nguyên tắc chính của lập trình.
Nếu bạn muốn tìm hiểu cách thức hoạt động của phần cứng và do đó có một số thiện cảm cơ học cho máy, bạn nên tìm hiểu mã máy, hay còn gọi là kiến trúc tập lệnh và cũng nghiên cứu cấu trúc bộ đệm của CPU hiện đại. Lưu ý rằng tôi không khuyến nghị ngôn ngữ lắp ráp, chỉ cần hiểu các hướng dẫn phần cứng, vì vậy bạn hiểu trình biên dịch tạo ra những gì.
Nếu bạn muốn học các nguyên tắc lập trình, hãy sử dụng một ngôn ngữ hiện đại như Java, C # hoặc Swift hoặc một trong hàng tá ngôn ngữ khác như Rust. Ngoài ra, nghiên cứu các loại mô hình lập trình khác nhau, bao gồm cả chức năng.
Hầu hết các ngôn ngữ lập trình được mô tả dưới dạng các máy trừu tượng. Sau đó, chúng được triển khai bằng cách sử dụng các bộ công cụ như trình biên dịch, trình liên kết, trình biên dịch, trình thông dịch, máy phân tích tĩnh, ngôn ngữ trung gian và phần cứng sẽ tạo ra một kết quả nhằm tôn vinh ít nhất tất cả các hành vi dự kiến của máy trừu tượng, như được quan sát bởi một chương trình .
C không phải là một ngoại lệ cho quy tắc trên. Nó được mô tả dưới dạng một cỗ máy trừu tượng không có khái niệm về phần cứng thực tế của bạn.
Như vậy, khi mọi người nói rằng C dạy cho bạn cách máy tính của bạn thực sự hoạt động, điều họ thường nói là C dạy cho bạn cách C hoạt động. Nhưng C rất phổ biến trong lập trình hệ thống, có thể hiểu rằng rất nhiều người bắt đầu nhầm lẫn nó với chính máy tính. Và cá nhân tôi sẽ đi xa hơn khi nói rằng việc biết C hoạt động như thế nào thường quan trọng hơn việc biết chính máy tính hoạt động như thế nào.
Tuy nhiên, C và máy tính là những thứ khác nhau. Phần cứng thực tế rất phức tạp - theo cách làm cho thông số C đọc giống như một cuốn sách dành cho trẻ em. Nếu bạn quan tâm đến cách phần cứng của bạn hoạt động, bạn luôn có thể tra cứu hướng dẫn và bắt đầu viết mã trong trình biên dịch. Hoặc bạn luôn có thể bắt đầu tìm hiểu về các mạch kỹ thuật số để bạn có thể tự thiết kế một số phần cứng. (Ít nhất, bạn sẽ đánh giá cao mức độ C là bao nhiêu.)
Được rồi, thực sự học về phần cứng liên quan đến những thứ khác ngoài C. Nhưng C có thể dạy bất cứ điều gì khác cho các lập trình viên ngày nay không?
Tôi nghĩ rằng nó phụ thuộc.
Đừng quá nhanh để chọn một trong những khả năng này. Tôi đã viết mã trong nhiều năm và tôi vẫn không biết câu nào là câu trả lời đúng, hoặc liệu câu trả lời đúng chỉ là một trong hai, hoặc liệu có một câu trả lời đúng về vấn đề này không.
Tôi hơi có xu hướng tin rằng cuối cùng bạn có thể nên áp dụng cả hai lựa chọn, một cách lỏng lẻo theo thứ tự tôi đã mô tả chúng. Nhưng tôi không nghĩ đây thực sự là một vấn đề kỹ thuật, tôi nghĩ đó là một vấn đề chủ yếu mang tính giáo dục. Mỗi người dường như học theo những cách khác nhau đáng kể.
Nếu bạn trả lời câu hỏi trên ít nhất là liên quan đến tùy chọn thứ hai mà tôi đã đề xuất, thì bạn đã có một vài câu trả lời trong vành đai của mình: mọi thứ có thể học bằng ngôn ngữ cấp cao hơn có thể được học tốt hơn bằng cách phát minh lại bằng C hoặc tại ít mở rộng nhất bằng cách thêm C vào hỗn hợp.
Nhưng, bất kể câu trả lời của bạn là gì, chắc chắn có một vài điều mà bạn có thể học gần như độc quyền từ C (và có lẽ là một số ít ngôn ngữ khác).
C là lịch sử quan trọng. Đó là một cột mốc mà bạn có thể nhìn vào và đánh giá cao nơi chúng tôi đến và có thể có thêm một chút bối cảnh về nơi chúng tôi sẽ đến. Bạn có thể đánh giá cao tại sao những hạn chế nhất định tồn tại và bạn có thể đánh giá cao những hạn chế nhất định đã được dỡ bỏ.
C có thể dạy bạn làm việc trong môi trường không an toàn. Nói cách khác, nó có thể huấn luyện bạn quan sát lưng khi ngôn ngữ (bất kỳ ngôn ngữ nào) không thể hoặc sẽ không làm điều đó cho bạn, vì bất kỳ lý do nào. Điều này có thể giúp bạn trở thành một lập trình viên tốt hơn ngay cả trong môi trường an toàn vì bạn sẽ tự tạo ra ít lỗi hơn và vì bạn sẽ có thể tắt an toàn tạm thời để giảm tốc độ thêm khỏi chương trình an toàn khác của bạn (ví dụ: sử dụng con trỏ trong C #), trong những trường hợp an toàn đi kèm với chi phí thời gian chạy.
C có thể dạy cho bạn rằng mọi đối tượng đều có yêu cầu lưu trữ, bố trí bộ nhớ, thực tế là bộ nhớ có thể được truy cập thông qua một không gian địa chỉ hữu hạn, v.v. Mặc dù các ngôn ngữ khác không cần sự chú ý của bạn về những vấn đề này, có một vài trường hợp trong đó một số trực giác có được có thể giúp bạn đưa ra quyết định sáng suốt hơn.
C có thể dạy cho bạn về các chi tiết của các tập tin liên kết và đối tượng và các vấn đề phức tạp khác thông qua hệ thống xây dựng của nó. Điều này có thể cung cấp cho bạn một sự hiểu biết thực hành hữu ích về cách một chương trình được biên dịch nguyên bản thường đi từ mã nguồn đến thực thi.
C có thể uốn cong tâm trí của bạn để suy nghĩ theo những cách mới lạ thông qua khái niệm hành vi không xác định. Hành vi không xác định là một trong những khái niệm yêu thích của tôi trong phát triển phần mềm, bởi vì nghiên cứu về ý nghĩa của nó đối với các trình biên dịch phi cổ điển là một bài tập tinh thần độc đáo mà bạn không thể có được từ các ngôn ngữ khác. Tuy nhiên, bạn sẽ phải từ chối thử và sai và bắt đầu nghiên cứu ngôn ngữ một cách cẩn thận và thận trọng trước khi bạn có thể đánh giá đầy đủ khía cạnh này.
Nhưng có lẽ nhận thức quan trọng nhất mà C có thể cấp cho bạn, là một ngôn ngữ nhỏ, là ý tưởng rằng tất cả các chương trình đều tập trung vào dữ liệu và hoạt động . Bạn có thể xem mọi thứ như các lớp mô-đun với hệ thống phân cấp và giao diện với công văn ảo hoặc các giá trị bất biến thanh lịch được vận hành bằng cách sử dụng các hàm toán học thuần túy. Và đó là tất cả tốt - nhưng C sẽ nhắc nhở bạn rằng tất cả chỉ là dữ liệu + hoạt động . Đó là một suy nghĩ hữu ích vì nó cho phép bạn đưa ra khá nhiều rào cản về tinh thần.
Lý do tại sao C tốt cho việc học không phải là nó dạy bất kỳ nguyên tắc nào . Nó dạy bạn, cách mọi thứ hoạt động .
C có thể được so sánh với một trong những chiếc xe cũ tốt từ những năm 70 hoặc 80, được chế tạo để lái. Bạn có thể xé chúng ra, vặn bằng vít và hiểu cách thức từng bộ phận hoạt động và cách thức hoạt động cùng với các bộ phận khác mà bạn có thể cầm trong tay để xem xét. Một khi bạn hiểu tất cả các bộ phận, bạn có một bức tranh rất rõ ràng làm thế nào toàn bộ hoạt động.
Ngôn ngữ hiện đại giống như một chiếc xe hơi hiện đại, trong đó động cơ về cơ bản là một hộp đen, quá phức tạp để có thể hiểu được bởi chủ sở hữu xe hơi trung bình. Những chiếc xe đó có thể làm rất nhiều, quái gì, trong những ngày này, chúng đang tích cực học lái xe. Và với sự phức tạp và thoải mái đó, giao diện người dùng đã được di chuyển ra xa hơn nhiều so với những gì đang thực sự diễn ra trong động cơ.
Khi bạn học lập trình bằng C, bạn tiếp xúc với rất nhiều ốc vít và đai ốc mà máy tính được tạo ra. Điều này cho phép bạn phát triển sự hiểu biết về chính máy. Chẳng hạn, nó cho phép bạn hiểu tại sao việc xây dựng một chuỗi dài như thế này không phải là một ý tưởng hay:
java.lang.String result = "";
for(int i = 0; i < components.size; i++) {
result = result + components[i];
};
(Tôi hy vọng, đây là Java chính xác, tôi đã không sử dụng nó trong một thời gian ...) Từ ví dụ mã này, không rõ tại sao vòng lặp có độ phức tạp bậc hai. Nhưng đó là trường hợp, và đó là lý do tại sao mã này sẽ dừng lại khi bạn có một vài triệu thành phần nhỏ để nối. Lập trình viên C có kinh nghiệm biết ngay vấn đề đang ở đâu và có thể sẽ tránh viết mã như vậy ngay từ đầu.
for(int i = 0; i < strlen(s); i++)
bằng C, vòng lặp cũng sẽ có độ phức tạp bậc hai và nó cũng không khó hiểu như trong ví dụ Java của bạn ;-)
Có những ngôn ngữ tốt hơn C để học "các nguyên tắc đằng sau lập trình", đặc biệt là các nguyên tắc lý thuyết, nhưng C có thể tốt để học một số điều thực tế, quan trọng về nghề thủ công. Câu trả lời của greyfade hoàn toàn chính xác, nhưng IMHO có nhiều thứ bạn có thể học từ C hơn là cách tự quản lý bộ nhớ. Ví dụ,
Làm thế nào để tạo các chương trình xử lý lỗi hoàn toàn trong trường hợp không có ngoại lệ
Làm thế nào để tạo cấu trúc trong một chương trình mà không cần bất kỳ sự hỗ trợ ngôn ngữ nào cho việc định hướng đối tượng
Làm thế nào để xử lý dữ liệu khi không có cấu trúc dữ liệu như danh sách kích thước động, từ điển hoặc trừu tượng chuỗi hữu ích
Làm thế nào để tránh các lỗi phổ biến như tràn mảng ngay cả khi trình biên dịch hoặc môi trường thời gian chạy không tự động cảnh báo bạn
Làm thế nào để tạo các giải pháp chung chung mà không cần hỗ trợ ngôn ngữ cho các mẫu hoặc chung chung
và tôi đã đề cập đến việc bạn có thể tự học cách quản lý bộ nhớ chưa? ;-)
Hơn nữa, bằng cách học C, bạn sẽ học được điểm tương đồng cú pháp của C ++, Java, C #, Objective C đến từ đâu.
Năm 2005, Joel Spolsky đã viết một đề nghị học C trước bất kỳ ngôn ngữ cấp cao nào khác. Lập luận của anh ấy là
"bạn sẽ không bao giờ có thể tạo mã hiệu quả bằng các ngôn ngữ cấp cao hơn."
"Bạn sẽ không bao giờ có thể làm việc trên các trình biên dịch và hệ điều hành, đó là một số công việc lập trình tốt nhất xung quanh."
"Bạn sẽ không bao giờ được tin tưởng để tạo ra kiến trúc cho các dự án quy mô lớn"
"Nếu bạn không thể giải thích tại sao sao while(*s++ = *t++);
chép một chuỗi hoặc nếu đó không phải là điều tự nhiên nhất trên thế giới đối với bạn, thì, bạn đang lập trình dựa trên sự mê tín
Tất nhiên, những gì anh ấy viết chắc chắn là có thể gây tranh cãi, nhưng IMHO rất nhiều lập luận của anh ấy vẫn còn hiệu lực cho đến ngày nay.
Hai tóm tắt cơ bản của điện toán là máy Turing và máy tính Lambda, và C là một cách để thử nghiệm quan điểm tính toán của máy Turing: chủ yếu là sự kế thừa của các hành động cấp thấp từ đó đưa ra kết quả mong muốn. Nhưng bạn phải nhớ rằng C đi kèm với mô hình tính toán của riêng nó. Vì vậy, học C sẽ dạy cho bạn các chi tiết cấp thấp của máy trừu tượng C, nó đang trở nên khá khác biệt so với các kiến trúc thực tế. Một trong những điều đầu tiên tôi được dạy trong C là không bao giờ cố gắng vượt qua trình biên dịch bằng cách áp dụng các thủ thuật "thông minh" và dường như xu hướng này ngày càng hướng tới việc tối ưu hóa nhiều hơn trong trình biên dịch. Giống như trong các ngôn ngữ cấp cao khác, khi bạn viết bằng C, trình biên dịch sẽ hiểu những gì bạn mong muốn được thực hiện trên máy C trừu tượng và thực hiện điều đó trên phần cứng thực tế,
Vì vậy, điều tôi muốn nói là việc học C không nhất thiết sẽ cho bạn một bức tranh tốt về những gì thực sự xảy ra trong phần cứng. "C gần với máy" nên được hiểu là "gần hơn hầu hết các ngôn ngữ cấp cao hơn". Học trực tiếp kiến trúc phần mềm sẽ trở nên bổ ích hơn nếu bạn muốn có một bức tranh chính xác hơn về "cách thức hoạt động".
Mặt khác, học C có thể giúp bạn làm quen với lập trình hệ thống, các loại cấp thấp, con trỏ và phân bổ bộ nhớ cụ thể. Đối với việc học các thuật toán và cấu trúc dữ liệu, tôi không có lợi thế để học chúng bằng C hơn là các ngôn ngữ khác.
Đó là câu hỏi kết thúc rất mở, có thể không trả lời kết luận. Bạn có thể học được khá nhiều thứ trong mọi ngôn ngữ với điều kiện bạn hiểu được nội bộ của khung ngôn ngữ. C buộc bạn phải hiểu chi tiết thấp hơn vì nó chủ yếu được thiết kế để viết một hệ điều hành. Ngay cả sau nhiều năm, nó vẫn là một trong những ngôn ngữ được sử dụng nhiều nhất chủ yếu nhờ vào các hệ thống nhúng và các dự án nguồn mở. Vì vậy, câu hỏi là những gì bạn muốn học? Và trong miền nào?