2009-04-24 39 views
8

Bạn nghĩ gì về một chức năng của dòng? Nó có tồi không? Một lợi thế mà tôi có thể nghĩ là nó làm cho mã toàn diện hơn (nếu bạn chọn một tên tốt cho nó). Ví dụ:Một chức năng của dòng trong C?

void addint(Set *S, int n) 
{ 
    (*S)[n/CHAR_SIZE] |= (unsigned char) pow(2, (CHAR_SIZE - 1) - (n % CHAR_SIZE)); 
} 

Một bất lợi tôi có thể nghĩ là nó làm chậm quá trình mã (đẩy các thông số để ngăn xếp, nhảy đến một chức năng, popping các thông số, làm phẫu thuật, nhảy trở lại mã - và chỉ cho một dòng?)

tốt hơn là nên đặt các dòng đó trong các hàm hoặc chỉ cần đặt chúng vào mã? Ngay cả khi chúng ta chỉ sử dụng chúng một lần?

BTW, tôi không tìm thấy bất kỳ câu hỏi nào về điều đó, vì vậy hãy tha thứ cho tôi nếu câu hỏi như vậy đã được hỏi trước đó.

+6

Bạn đang lo lắng về chi phí cuộc gọi, nhưng sau đó gọi pow để tăng 2 lên sức mạnh của một số nguyên nhỏ? ;-p –

+0

Điều gì có thể là cách tốt hơn để làm điều đó? Tôi muốn biết. –

+2

2^x cũng giống như 2 << x nếu x là một số nguyên –

Trả lời

21

Đừng sợ các chức năng 1 dòng!

Rất nhiều lập trình viên dường như có khối tâm thần về chức năng 1 dòng, bạn không nên.

Nếu nó làm cho mã rõ ràng hơn và sạch hơn, hãy trích dòng đó thành một hàm.

Hiệu suất có thể sẽ không bị ảnh hưởng.

Bất kỳ trình biên dịch nào được thực hiện trong thập kỷ qua (và có lẽ hơn nữa) sẽ tự động điền một hàm 1 dòng đơn giản. Ngoài ra, 1 dòng C có thể dễ dàng tương ứng với nhiều dòng mã máy. Bạn không nên giả sử rằng ngay cả trong trường hợp lý thuyết, nơi bạn phải chịu toàn bộ chi phí của một cuộc gọi hàm mà chi phí này là đáng kể so với "một dòng nhỏ" của bạn. Hãy để một mình quan trọng đối với hiệu suất tổng thể của ứng dụng của bạn.

Dẫn trừu tượng đến thiết kế tốt hơn. (Ngay cả đối với các dòng mã)

Các chức năng là các khối xây dựng chính của mã trừu tượng, thành phần, chúng không được bỏ qua. Nếu gói gọn một dòng mã đằng sau một cuộc gọi hàm làm cho mã dễ đọc hơn, hãy làm điều đó. Ngay cả trong trường hợp hàm được gọi một lần. Nếu bạn thấy điều quan trọng là phải nhận xét một dòng mã cụ thể, thì đó là một đoạn mã tốt có thể hữu ích khi di chuyển mã vào một hàm được đặt tên tốt.

Chắc chắn, mã đó có thể là 1 dòng ngày hôm nay, nhưng có bao nhiêu cách khác nhau để thực hiện cùng một chức năng? Mã đóng gói bên trong một hàm có thể giúp bạn dễ dàng xem tất cả các tùy chọn thiết kế có sẵn cho bạn. Có lẽ 1 dòng mã của bạn mở rộng thành một cuộc gọi đến một webservice, có thể nó sẽ trở thành một truy vấn cơ sở dữ liệu, có thể nó trở thành cấu hình (sử dụng mẫu chiến lược, ví dụ), có thể bạn muốn chuyển sang bộ nhớ đệm giá trị được tính bởi hàng. Tất cả các tùy chọn này dễ thực hiện hơn và dễ dàng hơn khi bạn trích xuất 1 dòng mã của bạn thành hàm riêng của nó.

Có thể 1 dòng của bạn nên có nhiều dòng hơn.

Nếu bạn có một khối mã lớn, bạn có thể bị nhồi nhét nhiều chức năng vào một dòng, chỉ để lưu trên màn hình bất động sản. Khi bạn di chuyển mã này sang một hàm, bạn giảm áp lực này, điều này có thể khiến bạn có khuynh hướng mở rộng lớp lót phức tạp của mình thành mã đơn giản hơn để lấy nhiều dòng (có khả năng cải thiện khả năng đọc và bảo trì của nó).

0

Nếu bạn sử dụng mã trong hàm đó 3 lần trở lên, thì tôi khuyên bạn nên đặt mã đó vào một hàm. Chỉ để bảo trì.

5

Nếu được sử dụng nhiều lần, hãy chắc chắn làm cho nó trở thành một hàm và để trình biên dịch thực hiện nội tuyến (có thể thêm "nội dòng" vào định nghĩa hàm). (< Lời khuyên thông thường về tối ưu hóa sớm sẽ xuất hiện tại đây >)

0

Ngôn ngữ nào? Nếu bạn có nghĩa là C, tôi cũng sẽ sử dụng bộ định tính inline. Trong C++, tôi có tùy chọn inline, boost.lamda hoặc và chuyển tiếp hỗ trợ gốc C++ 0x cho lamdas.

5

Vì ví dụ của bạn dường như đang sử dụng cú pháp C (++) mà bạn có thể muốn đọc lên trên inline functions giúp loại bỏ chi phí gọi hàm đơn giản. Từ khóa này chỉ là gợi ý cho trình biên dịch mặc dù nó có thể không inline tất cả các hàm mà bạn đánh dấu, và có thể chọn các hàm nội dòng không được đánh dấu.

.NET. JIT là các phương thức nội tuyến mà nó cảm thấy là thích hợp, nhưng bạn không kiểm soát được tại sao hoặc khi nó thực hiện điều này, mặc dù (như tôi hiểu nó), các bản dựng gỡ lỗi sẽ không bao giờ nội tuyến vì điều đó sẽ dừng mã nguồn khớp ứng dụng đã biên dịch.

8

Tôi không phải là người hâm mộ có tất cả các loại logic và chức năng va chạm vào một dòng. Ví dụ bạn đã hiển thị là một mớ hỗn độn và có thể được chia nhỏ thành nhiều dòng, sử dụng tên biến có ý nghĩa và thực hiện một thao tác này sau thao tác khác.

I khuyên bạn nên, trong mọi câu hỏi thuộc loại này, để có giao diện (mua, mượn, (không) tải xuống (miễn phí)) tại this book: Robert C. Martin - Clean Code. Đó là một cuốn sách mà mọi nhà phát triển đều nên xem xét.

Nó sẽ không làm cho bạn một coder tốt ngay lập tức và nó sẽ không ngăn bạn viết xấu mã trong tương lai, tuy nhiên nó sẽ làm cho bạn nhận ra nó khi bạn đang viết mã xấu xí. Nó sẽ buộc bạn phải nhìn vào mã của bạn với một con mắt quan trọng hơn và làm cho mã của bạn có thể đọc được như một câu chuyện trên báo.

1

Không có gì sai với một hàm dòng. Như đã đề cập, có thể cho trình biên dịch nội tuyến các hàm sẽ loại bỏ bất kỳ hình phạt hiệu suất nào.

Các chức năng cũng nên được ưu tiên hơn các macro vì chúng dễ debug, sửa đổi, đọc và ít có khả năng có các tác dụng phụ không mong muốn.

Nếu chỉ được sử dụng một lần thì câu trả lời sẽ ít rõ ràng hơn.Di chuyển nó đến một chức năng có thể làm cho chức năng gọi đơn giản hơn & rõ ràng hơn bằng cách di chuyển một số phức tạp vào chức năng mới.

-1

Đôi khi nó không phải là một ý tưởng tồi để sử dụng tiền xử lý:

#define addint(S, n) (*S)[n/CHAR_SIZE] |= (unsigned char) pow(2, (CHAR_SIZE - 1) - (n % CHAR_SIZE)); 

Cấp, bạn không nhận được bất kỳ loại kiểm tra kiểu, nhưng trong một số trường hợp này có thể hữu ích. Macros có nhược điểm và lợi thế của họ, và trong một vài trường hợp nhược điểm của họ có thể trở thành lợi thế. Tôi là một fan hâm mộ của các macro ở những nơi thích hợp, nhưng đó là vào bạn để quyết định khi nào là thích hợp. Trong trường hợp này, tôi sẽ đi ra ngoài một chi và nói rằng, bất cứ điều gì bạn kết thúc làm, rằng một dòng mã là khá một chút.

#define addint(S, n) do { \ 
    unsigned char c = pow(2, (CHAR_SIZE -1) - (n % CHAR_SIZE)); \ 
    (*S)[n/CHAR_SIZE] |= c \ 
    } while(0) 
+2

Quoth bộ tiền xử lý: "Lạm dụng tôi, Lạm dụng tôi, Làm cho tôi cảm thấy muốn!" –

+1

Tôi chỉ cảm thấy như nó nên được đề cập đến cho đầy đủ. Nó có thể không phải là giải pháp tốt nhất trong trường hợp này, bởi vì không có kiểm tra loại, nhưng tôi đề cập đến điều đó. Tôi không nói "(ab) sử dụng bộ tiền xử lý", tôi đang nói "đừng quên về bộ tiền xử lý". Nó không phải là xấu của một công cụ. –

+0

Tôi đồng ý rằng bộ tiền xử lý là một công cụ rất hữu ích. Tuy nhiên, khi một cái gì đó được phức tạp, nó thường tốt hơn để nội tuyến nó, nhìn vào bãi chứa asm và xem nếu trình biên dịch của bạn đồng ý. 8/10 lần, trình biên dịch sẽ chính xác. Bây giờ, nếu trình biên dịch của bạn chỉ là một lỗ A ** và bạn biết nó, vẫn còn là bộ tiền xử lý. –

Các vấn đề liên quan