🌱 Embedded C - Toàn bộ về Hàm - Function và những khái niệm liên quan

🌱 Embedded C - Toàn bộ về Hàm - Function và những khái niệm liên quan

    Hàm - Function là một khái niệm phổ biến trong lập trình nói chung và lập trình C nói riêng, ngay từ bài học đầu tiên về lập trình, chắc hẳn bạn đã nhìn thấy hàm main().

    Bài viết này sẽ cùng bàn về các khái niệm về Function trong C, cách tạo một hàm, nó được gọi như thế nào, sử dụng như thế nào và các vấn đề có thể gặp phải khi làm việc với Function!


Mục Lục


Khái niệm chung về Function

    Một cách dễ hiểu, Function - Hàm là một đoạn code (hoặc mã lệnh) thực hiện một tác vụ cụ thể, có tên, và có thể gọi ra để sử dụng ở những vị trí khác trong chương trình.

    Hàm giúp chia nhỏ chương trình thành các phần dễ quản lý. Mọi chương trình C đều có ít nhất một hàm main(), các hàm trong thư viện C chuẩn (ví dụ printf, scanf, ...) và có thể định nghĩa thêm các hàm khác. Hàm mang lại rất nhiều lợi ích:

  • Tổ chức Code: Giúp code dễ đọc, bảo trì, và tái sử dụng, đặc biệt trong hệ thống phức tạp.
  • Tối ưu hóa tài nguyên: Hàm chỉ chiếm bộ nhớ 1 lần và có thể sử dụng nhiều lần, giúp cho code tránh lặp đi lặp lại.

    Bài viết sẽ chỉ nhắc đến các hàm mà người dùng tự định nghĩa, thay vì các hàm trong thư việc C chuẩn. Dưới đây là cách tạo một hàm:

return_type function_name(argument_list) {
    // Function Body
}

  • argument_list là tập hợp các tham số truyền vào, ngăn cách nhau bởi dấu phẩy, nếu không thích truyền gì vào thì để là void.
  • return_type thì chỉ có một thay vì list, nếu không thích trả về gì thì để là void.
  • function_name cũng có cách đặt tên như Variable.

    ↪ Sau khi được định nghĩa thì hàm có thể được gọi (call) bằng cách sử dụng tên của nó, truyền tham số vào nếu có, và có thể gán vào một biến nếu có trả về giá trị.

Embedded C Function

    Các khái niệm cơ bản về hàm mình đề cập trong video sau:

Bàn về Function Call

    Đối với Embedded C, việc hiểu một chút về kiến trúc máy tính là vô cùng quan trọng. Ở đây, ta bàn đến khái niệm Function Call, tức là khi một hàm được gọi thì CPU làm những điều gì, chiếm bao nhiêu bộ nhớ? Việc này giúp ích rất nhiều cho việc hiểu và tối ưu hóa chương trình, đặc biệt nơi những vi điều khiển có bộ nhớ nhỏ và cần tối ưu về cả tốc độ thực thi.

    Mình có một bài viết chi tiết về Function Call tại đây cũng như đề cập trong video ở trên!


Pass by value & Pass by Reference

    Ops, với khái niệm Function call kể trên, khi call hàm thì số lượng và kích thước tham số ảnh hưởng lớn đến bộ nhớ Stack (Một bộ nhớ thường được cấp kích thước khá nhỏ trong Vi điều khiển). Vậy nếu tham số truyền vào là một struct kích thước lớn thì sao?

  1. #include <stdio.h>
  2. #include <stdint.h>
  3. typedef struct {
  4. uint8_t A;
  5. uint32_t B[100];
  6. } TestType; // Size > 400 bytes!
  7. void Test_Struct(TestType X) // X takes up a lot of Stack Memory
  8. {
  9. // Handle X
  10. }
  11. int main() {
  12. TestType A;
  13. Test_Struct(A); // Beware Stack Overflow
  14. }

    Dễ thấy việc này cực kỳ nguy hiểm với bộ nhớ stack! và cũng làm tốn thời gian copy dữ liệu lên trên bộ nhớ.

    Vậy nên, C hỗ trợ 2 cách truyền tham số vào hàm là Pass by Value và Pass by Reference. Chi tiết về phần này mình đặt ở bài viết bên dưới!


Một số Function đặc biệt

    C hỗ trợ một số Function đặc biệt so với các hàm khác!

Sự thật về main() Function

    Dễ thấy, khi bắt đầu học thì ta thấy main() là hàm đầu tiên được gọi trong chương trình C. Thực tế, khi học về Vi điều khiển, bạn sẽ biết đến khái niệm Reset Sequence, phụ thuộc vào kiến trúc core, nó sẽ thực thi đoạn code đầu tiên ở một vị trí cố định nào đó, thường được đặt Reset_Handler (Hàm reset) để xử lý các vấn đề khởi tạo hệ thống, trước khi gọi hàm main().

    Vì vậy, main là một hàm được gọi (không phải đầu tiên), và cũng có thể truyền tham số. Prototype đầy đủ của main() function:

int main(int argc, char *argv[]) { /* ... */ }

    Bài viết chi tiết về argc và argv, ứng dụng và cách sử dụng:


Inline Function

    Một cách để tối ưu hóa việc các hàm bị call nhiều lần
    Inline Function

Số lượng tham số linh hoạt với Variadic Function

    Tại sao các hàm như printf() lại có thể truyền số lượng tham số khác nhau mỗi lần sử dụng, hãy cũng tìm hiểu Variadic Function!

Kết Luận

    Nhìn chung, hàm trong C cực kỳ đa dạng và thường xuyên được sử dụng, vì vậy, bạn nên nắm được quá trình Function Call, cũng như tách biệt chức năng của các hàm một cách rõ ràng để tối ưu hóa chương trình một cách tốt nhất.

    Việc sử dụng các hàm sao cho hiệu quả cũng rất quan trọng, có những lỗi liên quan đến bộ nhớ và tốc độ khi sử dụng hàm mà dev cần lưu ý, chẳng hạn Recursion (Đệ quy) sẽ được đề cập trong các bài viết sau!

>>>>>> Follow ngay <<<<<<<

Để nhận được những bài học miễn phí mới nhất nhé 😊
Chúc các bạn học tập tốt 😊

Nguyễn Văn Nghĩa

Mình là một người thích học hỏi và chia sẻ các kiến thức về Nhúng IOT.

Đăng nhận xét

Mới hơn Cũ hơn
//