2008-08-10 37 views
17

Tôi đã làm việc trên một số hệ thống nhúng khác nhau. Họ đã sử dụng tất cả typedef s (hoặc #defines) cho các loại như UINT32.Khi nào tôi nên sử dụng kiểu trừu tượng trong các hệ thống nhúng

Đây là một kỹ thuật tốt vì nó thúc đẩy nhà kích thước của các loại để các lập trình viên và làm cho bạn ý thức hơn về cơ hội cho tràn, vv

Nhưng trên một số hệ thống bạn biết rằng trình biên dịch và xử lý sẽ không thay đổi cho cuộc sống của dự án.

Vậy điều gì sẽ ảnh hưởng đến quyết định của bạn để tạo và thực thi các loại dự án cụ thể?

EDIT Tôi nghĩ rằng mình đã mất được ý chính của câu hỏi của mình và có thể thực sự là hai.

Với chương trình nhúng, bạn có thể cần loại kích thước cụ thể cho giao diện và cũng để đối phó với các tài nguyên bị hạn chế như RAM. Điều này không thể tránh được, nhưng bạn có thể chọn sử dụng các kiểu cơ bản từ trình biên dịch.

Đối với mọi thứ khác, các loại này ít quan trọng hơn.
Bạn cần phải cẩn thận không gây tràn và có thể cần xem ra để đăng ký và sử dụng ngăn xếp. Điều này có thể dẫn bạn đến UINT16, UCHAR. Tuy nhiên, việc sử dụng các loại như UCHAR có thể thêm trình biên dịch 'fluff'. Bởi vì thanh ghi thường lớn hơn, một số trình biên dịch có thể thêm mã để buộc kết quả vào loại.

i++;
có thể trở thành
ADD REG,1 
AND REG, 0xFF
không cần thiết.

Vì vậy, tôi nghĩ rằng câu hỏi của tôi cần phải có được: -

cho những hạn chế của phần mềm nhúng những gì là chính sách tốt nhất để đặt cho một dự án mà sẽ có nhiều người làm việc trên nó - không phải tất cả trong số họ sẽ được cùng một mức độ kinh nghiệm.

Trả lời

16

Tôi sử dụng kiểu trừu tượng rất hiếm khi. Dưới đây là lập luận của tôi, sắp xếp theo thứ tự tăng dần của tính chủ quan:

  1. biến địa phương khác với các thành viên struct và mảng theo nghĩa là bạn muốn họ để phù hợp với một thanh ghi. Trên một mục tiêu 32b/64b, một địa phương int16_t có thể làm cho mã chậm hơn so với một int địa phương kể từ khi trình biên dịch sẽ phải thêm hoạt động để/lực lượng/tràn theo ngữ nghĩa của int16_t. Trong khi C99 định nghĩa một kiểu chữ là intfast_t, AFAIK một int đơn giản cũng sẽ vừa trong sổ đăng ký, và chắc chắn nó là tên ngắn hơn.

  2. Các tổ chức thích những typedef này hầu như luôn kết thúc với một số trong số chúng (INT32, int32_t, INT32_T, ad infinitum). Do đó, các tổ chức sử dụng các loại được tích hợp sẵn hơn, theo một cách, chỉ có một bộ tên. Tôi muốn mọi người sử dụng typedefs từ stdint.h hoặc windows.h hoặc bất kỳ thứ gì hiện có; và khi một mục tiêu không có tệp .h đó, làm cách nào để thêm mục tiêu?

  3. Các typedefs về mặt lý thuyết có thể hỗ trợ tính di động, nhưng tôi, đối với một, không bao giờ đạt được điều gì từ chúng. Có một hệ thống hữu ích mà bạn có thể chuyển từ mục tiêu 32b sang mục tiêu 16b không? Có một hệ thống 16b đó là không tầm thường để cổng đến một mục tiêu 32b? Hơn nữa, nếu hầu hết các vars là ints, bạn sẽ thực sự đạt được một cái gì đó từ 32 bit trên mục tiêu mới, nhưng nếu chúng là int16_t, bạn sẽ không. Và những nơi khó có thể yêu cầu kiểm tra thủ công; trước khi bạn thử một cổng, bạn không biết chúng ở đâu. Bây giờ, nếu ai đó nghĩ rằng nó rất dễ dàng để port mọi thứ nếu bạn có typedefs trên tất cả các nơi - khi thời gian đến cổng, mà xảy ra với vài hệ thống, viết một kịch bản chuyển đổi tất cả các tên trong cơ sở mã. Điều này sẽ hoạt động theo logic "không cần kiểm tra thủ công" và trì hoãn nỗ lực đến thời điểm thực sự mang lại lợi ích.

  4. Bây giờ nếu tính di động có thể là một lợi ích lý thuyết của typedefs, thì khả năng đọc chắc chắn sẽ bị hỏng. Chỉ cần nhìn vào stdint.h: {int,uint}{max,fast,least}{8,16,32,64}_t. Rất nhiều loại. Một chương trình có rất nhiều biến; thực sự là dễ hiểu mà cần phải là int_fast16_t và cần phải là uint_least32_t? Đã bao nhiêu lần chúng ta âm thầm chuyển đổi giữa chúng, làm cho chúng hoàn toàn vô nghĩa? (Tôi đặc biệt thích BOOL/Bool/eBool/boolean/bool/int chuyển đổi. Mỗi chương trình được viết bởi một tổ chức có trật tự bắt buộc typedefs là rải rác với điều đó).

  5. Tất nhiên trong C++, chúng tôi có thể làm cho hệ thống kiểu trở nên nghiêm ngặt hơn, bằng cách gói số trong instantiation lớp mẫu với các toán tử và công cụ quá tải. Điều này có nghĩa là bây giờ bạn sẽ nhận được thông báo lỗi của biểu mẫu "số Lớp < int, Ít nhất, 32 > không có toán tử + quá tải đối với loại lớp số < unsigned long long, Fast, 64 >, ứng cử viên là ..." I đừng gọi đây là "khả năng đọc". Cơ hội của bạn thực hiện các lớp bao bọc chính xác là vi mô, và hầu hết thời gian bạn sẽ chờ đợi cho các mẫu instantumerable vô biên để biên dịch.

+0

Một tinh chỉnh khác mà tôi đã thấy và đánh giá cao là sử dụng các loại FIXED và các loại "USE BEST". ví dụ: typedef unsigned char UINT8 typedef unsigned uint255; uint 255 chỉ định phạm vi giá trị, nhưng cho phép kích thước tối ưu được chỉ định cho mỗi hệ thống – itj

+0

@itj: Thay vì uint255, sử dụng 'uint_fast8_t' từ' stdint.h'. Nó được định nghĩa là kiểu nhanh có thể hỗ trợ giá trị 8 bit không dấu. Trên một nền tảng, đó có thể là một 'unsigned char'. Ngày khác nó có thể chỉ đơn giản là một 'unsigned int'. – tomlogic

+0

Điều này là tốt cho đến khi mã của bạn phải hoạt động trên một bộ xử lý rất hạn chế và bạn muốn hoặc phải thử nghiệm trên một bộ xử lý khác, có lẽ vì thử nghiệm và gỡ lỗi trên đích thực là khó/không thể. Trong tình huống này, bạn cần phải thử nghiệm trên máy chủ lưu trữ của bạn với các biến có cùng kích thước với mục tiêu và nếu bạn đã mã hóa bằng typedefs kích thước cụ thể, quy trình của bạn sẽ hoàn toàn bị bẻ khóa. – barny

1

Tính nhất quán, tiện lợi và dễ đọc. "UINT32" dễ đọc hơn và có thể ghi hơn "unsigned long long", tương đương với một số hệ thống.

Ngoài ra, trình biên dịch và bộ xử lý có thể được sửa cho cuộc đời của một dự án, nhưng mã từ dự án đó có thể tìm thấy cuộc sống mới trong một dự án khác. Trong trường hợp này, việc có các kiểu dữ liệu nhất quán rất thuận tiện.

7

Chuẩn C99 có một số loại số nguyên có kích thước chuẩn. Nếu bạn có thể sử dụng một trình biên dịch hỗ trợ C99 (gcc không), bạn sẽ tìm thấy chúng trong <stdint.h> và bạn chỉ có thể sử dụng chúng trong các dự án của bạn.

Ngoài ra, nó có thể đặc biệt quan trọng trong các dự án nhúng để sử dụng các loại như một loại "mạng lưới an toàn" cho những thứ như chuyển đổi đơn vị. Nếu bạn có thể sử dụng C++, tôi hiểu rằng có một số thư viện "unit" cho phép bạn làm việc trong các đơn vị vật lý được xác định bởi hệ thống kiểu C++ (thông qua các mẫu) được biên dịch như các phép toán trên các kiểu vô hướng cơ bản. Ví dụ: các thư viện này sẽ không cho phép bạn thêm distance_t vào số mass_t vì các đơn vị không xếp hàng; bạn sẽ thực sự gặp lỗi trình biên dịch.

Thậm chí nếu bạn không thể làm việc trong C++ hoặc ngôn ngữ khác cho phép bạn viết mã theo cách đó, bạn ít nhất có thể sử dụng hệ thống loại C để giúp bạn nắm bắt các lỗi như vậy bằng mắt. (Đó thực sự là ý định ban đầu của ký hiệu Hungary của Simonyi.) Chỉ vì trình biên dịch sẽ không hét lên với bạn khi thêm meter_t vào một gram_t không có nghĩa là bạn không nên sử dụng các loại như thế. Đánh giá mã sẽ hiệu quả hơn nhiều khi phát hiện ra lỗi đơn vị.

4

Ý kiến ​​của tôi là nếu bạn đang tùy thuộc vào mức tối thiểu/tối đa/kích thước cụ thể không chỉ cho rằng (nói) một unsigned int là 32 byte - sử dụng uint32_t thay vì (giả sử biên dịch của bạn hỗ trợ C99).

4

Tôi thích sử dụng stdint.h loại để xác định các API hệ thống cụ thể bởi vì chúng rõ ràng nói các mục lớn như thế nào. Quay trở lại những ngày cũ của Palm OS, các API hệ thống được định nghĩa bằng cách sử dụng một loạt các loại mơ hồ như "Word" và "SWord" được thừa hưởng từ Mac OS rất cổ điển. Họ đã làm sạch để thay vì nói Int16 và nó làm cho API dễ dàng hơn cho người mới đến để hiểu, đặc biệt là với các vấn đề con trỏ 16-bit lạ trên hệ thống đó. Khi họ thiết kế Palm OS Cobalt, họ đã đổi tên một lần nữa để phù hợp với tên của stdint.h, làm cho nó rõ ràng hơn và giảm số lượng typedef mà họ phải quản lý.

+0

+1 để sử dụng các loại trong 'stdint.h'. Cách tốt nhất để đi cho tính di động. Nếu một nền tảng không có nó, nó tầm thường để tạo ra nó. – tomlogic

3

Tôi tin rằng các tiêu chuẩn của MISRA đề xuất (yêu cầu?) Việc sử dụng typedef.

Từ góc độ cá nhân, sử dụng typedefs không để lại nhầm lẫn về kích thước (tính bằng bit/byte) của một số loại nhất định. Tôi đã thấy các nhà phát triển hàng đầu cố gắng cả hai cách phát triển bằng cách sử dụng các loại tiêu chuẩn, ví dụ: int và sử dụng các loại tùy chỉnh, ví dụ: UINT32.

Nếu mã không phải là di động có rất ít thực lợi ích trong việc sử dụng typedefs, tuy nhiên, nếu như tôi thì bạn làm việc trên cả hai loại phần mềm (di động và cố định môi trường) sau đó nó có thể hữu ích để giữ một tiêu chuẩn và sử dụng các loại cutomised. Ít nhất như bạn nói, các lập trình viên sau đó rất nhiều nhận thức về bao nhiêu bộ nhớ mà họ đang sử dụng. Một yếu tố khác để xem xét là làm thế nào 'chắc chắn' là bạn rằng mã sẽ không được chuyển sang môi trường khác? Ive thấy bộ xử lý mã cụ thể phải được dịch như là một phần cứng engieer đã đột nhiên đã phải thay đổi một hội đồng quản trị, đây không phải là một tình huống tốt đẹp để được ở nhưng do typedefs tùy chỉnh nó có thể có được rất nhiều tồi tệ hơn!

+0

Vâng, đó là quy tắc tư vấn * (# 6.3 của MISRA-C 2004 tương ứng # 13 của MISRA-C '98) *. – ollo

0

Có lẽ tôi kỳ lạ, nhưng tôi sử dụng ub, ui, ul, sb, si và sl cho các loại số nguyên của tôi. Có lẽ "i" cho 16 bit có vẻ hơi ngày, nhưng tôi thích giao diện của ui/si tốt hơn so với uw/sw.

+0

Tôi đoán số tiền này dựa trên ngữ cảnh. Đối với lập trình nhúng, kích thước là rất quan trọng vì vậy i & w có hiệu quả "không quan tâm" giá trị. – itj

+0

@itj: Tôi không chắc chắn ý bạn là gì. Tôi sử dụng số nhận dạng loại hai ký tự của mình vì chúng ngắn gọn và rõ ràng và rõ ràng. Tôi không thể nghĩ ra bất kỳ định danh 2 ký tự nào khác mà tôi sử dụng cho bất kỳ mục đích nào bắt đầu bằng 's' hoặc 'u', do đó, có vẻ như rõ ràng ý nghĩa của các loại (ngoại trừ, có thể, đối với 'ui' hoặc 'si' bị cô lập). – supercat

1

Nếu hệ thống nhúng của bạn là bằng cách nào đó một an toàn hệ thống quan trọng (hoặc tương tự), nó mạnh mẽ khuyên (nếu không cần thiết) để sử dụng typedefs so với các loại đồng bằng.

TK. đã nói trước đây, Misra-C có (tư vấn) quy tắc để làm như vậy:

Rule 6.3 (tư vấn): typedefs mà chỉ ra kích thước và signedness nên được sử dụng thay cho các loại số cơ bản .

(từ Misra-C năm 2004; nó Rule # 13 (adv) của Misra-C 1998)


Same cũng áp dụng cho C++ trong lĩnh vực này; ví dụ. JSF C++ coding standards:

AV Rule 209 tập tin Một UniversalTypes sẽ được tạo ra để xác định tất cả sta loại ndard cho các nhà phát triển để sử dụng. Các loại bao gồm: [uint16, int16, uint32_t etc.]

1

Sử dụng <stdint.h> làm cho mã của bạn dễ dàng hơn để thử nghiệm đơn vị trên máy tính.

Nó có thể cắn bạn khá khó khăn khi bạn có kiểm tra cho tất cả mọi thứ nhưng nó vẫn phá vỡ trên hệ thống đích của bạn bởi vì một int đột nhiên chỉ dài 16 bit.

+0

Vâng, đây là một trong những minh chứng thực tế nhất khi sử dụng các loại kích thước rõ ràng có ý nghĩa rất lớn. Tất nhiên, nếu bạn không/sẽ không bao giờ thử nghiệm trên máy tính thì tại sao bạn lại quan tâm? – barny

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