2010-08-22 27 views
8

Tôi đang định sử dụng Arduino programmable board. Những bộ nhớ này có các ký ức flash khá giới hạn nằm trong khoảng từ 16 đến 128 kB để lưu trữ mã C hoặc C++ đã biên dịch.Bao nhiêu là 32 kB mã được biên dịch

Có cách nào để ước tính bao nhiêu (mã chuẩn) nó sẽ đại diện?

Tôi cho rằng điều này rất mơ hồ, nhưng tôi chỉ đang tìm kiếm thứ tự độ lớn.

+19

64k là đủ cho mọi người! –

+3

16kB đại diện cho bất cứ nơi nào từ "một phần mười kích thước cần thiết cho thời gian chạy tự động liên kết" đến "khoảng một nghìn câu", sau này giả định trung bình 16 byte cho một câu lệnh được biên dịch. –

+0

đảm bảo không phân bổ tĩnh bất kỳ bộ đệm lớn nào. – Anon

Trả lời

6

Đầu ra của lệnh size là nơi bắt đầu tốt, nhưng không cung cấp cho bạn tất cả thông tin bạn cần.

$ avr-size program.elf 
text   data bss  dec  hex filename 

Kích thước hình ảnh của bạn thường lớn hơn một chút so với tổng của văn bản và phần dữ liệu. Phần bss về cơ bản được nén bởi vì nó là tất cả 0. Có thể có các phần khác có liên quan không được liệt kê theo kích thước.

Nếu hệ thống xây dựng của bạn được thiết lập giống như hệ thống tôi đã sử dụng trước đây cho bộ vi điều khiển AVR thì bạn sẽ kết thúc với tệp * .elf cũng như tệp * .bin và có thể là tệp * .hex. Tệp * .bin là hình ảnh thực tế sẽ được lưu trữ trong flash chương trình của bộ xử lý, vì vậy bạn có thể kiểm tra kích thước của nó để xác định cách chương trình của bạn đang phát triển khi bạn thực hiện chỉnh sửa cho nó. Tệp * .bin được trích xuất từ ​​tệp * .elf bằng lệnh objdump và một số cờ mà tôi không thể nhớ ngay bây giờ.

Nếu bạn muốn biết cách đoán thời gian mã C hoặc C++ của bạn sẽ sản xuất ra sao khi được biên dịch, điều này sẽ khó khăn hơn rất nhiều. Tôi đã quan sát thấy một blowup 10x trong một chức năng khi tôi đã cố gắng sử dụng một uint64_t chứ không phải là một uint32_t khi tất cả tôi đã làm được incrementing nó (này là khoảng 5 lần nhiều mã hơn tôi nghĩ rằng nó sẽ được). Điều này chủ yếu là để làm với tối ưu hóa avc của gcc không phải là tốt nhất, nhưng thay đổi nhỏ hơn trong kích thước mã có thể leo từ mã dường như vô tội.

Điều này có thể sẽ được khuếch đại với việc sử dụng C++, có xu hướng ẩn nhiều thứ biến thành mã hơn C. Trưởng trong số những điều C++ ẩn là các cuộc gọi destructor và rất nhiều dereferencing con trỏ mà phải làm với con trỏ this trong các đối tượng cũng như một con trỏ bí mật nhiều đối tượng có bảng chức năng ảo của họ và các biến tĩnh lớp.

Trên AVR tất cả các công cụ con trỏ này có thể thực sự thêm lên vì con trỏ lớn gấp hai lần sổ đăng ký và thực hiện nhiều hướng dẫn để tải. Ngoài ra AVR chỉ có một vài cặp đăng ký có thể được sử dụng như con trỏ, dẫn đến rất nhiều thứ di chuyển vào và ra khỏi những thanh ghi đó.

Một số lời khuyên cho các chương trình nhỏ trên AVR:

  • Sử dụng uint8_tint8_t thay vì int bất cứ khi nào bạn có thể. Bạn cũng có thể sử dụng và int_fast8_t nếu bạn muốn mã của mình có thể di động. Điều này có thể dẫn đến nhiều thao tác chỉ chiếm một nửa mã, vì int là hai byte.

  • Phải rất ý thức về những thứ như chuỗi và cấu trúc hằng số và chữ và cách thức/vị trí chúng được lưu trữ.

  • Nếu bạn không sợ nó, hãy đọc hướng dẫn lắp ráp AVR.Bạn có thể có ý tưởng về các loại hướng dẫn và từ đó loại mã C dễ dàng ánh xạ tới các hướng dẫn đó. Sử dụng loại mã C đó.

+0

Cảm ơn bạn đã trả lời, đặc biệt là cho tất cả các lời khuyên thực tế. – Klaus

+0

@Klaus: Nếu bạn nghĩ câu trả lời hữu ích, bạn nên đánh dấu câu trả lời là câu trả lời được chấp nhận. :) –

+0

Điều này rất lý thuyết. Những gì tôi tìm kiếm và những gì tôi tưởng tượng rất nhiều người mới tìm kiếm micros là những ví dụ đơn giản và một cách để đánh giá kích cỡ của thư viện, làm thế nào lớn là một số đơn giản LED PWM thực hiện trong C so với C + +, có một danh sách các kích cỡ chung thư viện được sử dụng trên Arduino, những thứ như thế. – Nobody

3

Bạn thực sự không thể nói ở đó. Độ dài của mã chưa được biên dịch ít có liên quan đến độ dài của mã được biên dịch. Ví dụ:

#include <iostream> 
#include <vector> 
#include <string> 
#include <algorithm> 

int main() 
{ 
    std::vector<std::string> strings; 
    strings.push_back("Hello"); 
    strings.push_back("World"); 
    std::sort(strings.begin(), strings.end()); 
    std::copy(strings.begin(), strings.end(), std::ostream_iterator<std::string>(std::cout, "")); 
} 

vs

#include <iostream> 
#include <vector> 
#include <string> 
#include <algorithm> 

int main() 
{ 
    std::vector<std::string> strings; 
    strings.push_back("Hello"); 
    strings.push_back("World"); 
    for (int idx = 0; idx < strings.size(); idx++) 
    std::cout << strings[idx]; 
} 

Cả hai đều là những con số chính xác cùng một dòng, và cho kết quả tương tự, nhưng ví dụ đầu tiên liên quan đến một instantiation của std :: sắp xếp, mà có lẽ là một thứ tự mã độ lớn hơn phần còn lại của mã ở đây.

Nếu bạn hoàn toàn cần đếm số byte được sử dụng trong chương trình, hãy sử dụng trình kết hợp.

+2

tất cả ngoại trừ câu cuối cùng! mọi người vui vẻ viết mã trong C (và C++) trong môi trường không gian hạn chế. –

+1

Ngay cả khi sử dụng assembler, bạn sẽ cần phải biết bao nhiêu byte mỗi lệnh, vì (ít nhất là trên một số nền tảng) không có mối quan hệ cố định giữa các bộ nhớ và các assembly. Vì vậy, một trong hai cách bạn sẽ được biên dịch/lắp ráp mã và xem kết quả là lớn như thế nào. –

+0

@Kieth: Tôi chưa bao giờ nói rằng bạn phải sử dụng bộ lắp ráp trong môi trường không gian hạn chế. Tôi nói rằng nếu bạn cần phải * hoàn toàn chắc chắn * như thế nào kích thước mã sẽ ảnh hưởng đến kích thước nhị phân, đó là những gì bạn phải làm. Số lượng mã được tạo ra không tỷ lệ thuận với kích thước mã đầu vào, ngay cả trong C và C++. @Pete: Điều này đúng - mọi nền tảng tôi từng viết là trình biên dịch cho các lệnh cố định chiều rộng cố định (PIC và MIPS). Tất nhiên nếu bạn đang viết một cái gì đó giống như x86 thậm chí lắp ráp thậm chí không thể giúp bạn, nhưng ít nhất nó sẽ liên quan trực tiếp đến kích thước chương trình hơn so với mã nguồn C hoặc C++. –

0

Tại hệ thống Linux, bạn có thể thực hiện một số thử nghiệm với các chương trình ví dụ được biên dịch tĩnh. Ví dụ.

$ size `which busybox ` 
text   data bss  dec  hex filename 
1830468 4448 25650 1860566 1c63d6 /bin/busybox 

Kích thước được tính bằng byte. Đầu ra này độc lập với định dạng tệp thực thi, vì kích thước của các phần khác nhau bên trong định dạng tệp. Phần văn bản có chứa mã máy và công cụ const. Phần dữ liệu chứa dữ liệu để khởi tạo tĩnh các biến. Kích thước bss là kích thước của dữ liệu chưa được khởi tạo - tất nhiên dữ liệu chưa được khởi tạo không cần phải được lưu trữ trong tệp thi hành.)

Vâng, busybox chứa rất nhiều chức năng (như tất cả các lệnh shell thông thường, vỏ…) .

Nếu bạn liên kết các ví dụ riêng với gcc -static, hãy nhớ rằng libc đã sử dụng của bạn có thể tăng đáng kể kích thước chương trình và sử dụng libc được nhúng có thể hiệu quả hơn nhiều.

Để kiểm tra xem bạn có thể xem diet-libc hoặc uclibc và liên kết với điều đó không. Trên thực tế, busybox thường được liên kết với uclibc.

Lưu ý rằng kích thước bạn nhận theo cách này chỉ cung cấp cho bạn một đơn đặt hàng có độ lớn. Ví dụ, máy trạm của bạn có thể sử dụng kiến ​​trúc CPU khác so với bảng arduino và mã máy của kiến ​​trúc khác nhau, có thể khác nhau, nhiều hơn hoặc ít hơn, về kích thước của nó (vì kích thước toán hạng, hướng dẫn có sẵn, mã hóa opcode và một).

Để tiếp tục với thứ tự thô về độ lớn lý do, busybox chứa khoảng 309 tools (bao gồm ftp daemon và các công cụ tương tự), tức là kích thước mã trung bình của công cụ hộp thư là khoảng 5k.

+0

Tôi không thấy trong bất kỳ cách nào như thế này là Linux cụ thể. Windows có các tiện ích tương tự, ví dụ: FileAlyzer. Unixen khác hoàn toàn có thể sử dụng kích thước là tốt, không chỉ là Linux. –

+0

Ở đây kích thước tệp là 183 kB? Tôi không quen thuộc với lệnh 'size' (xấu hổ với tôi). – Klaus

+0

Điều này sẽ không mang tính đại diện, bạn sẽ kéo các thư viện khổng lồ (realtive) và chi phí của định dạng elf, nó sẽ rất lớn so với một hệ nhị phân trên arduino. – nos

1

Đó là khá một chút cho một phần hợp lý phức tạp của phần mềm, nhưng bạn sẽ bắt đầu va chạm vào giới hạn nếu bạn muốn nó có nhiều chức năng khác nhau. Ngoài ra, nếu bạn muốn lưu trữ khá nhiều chuỗi tĩnh và dữ liệu, nó có thể ăn vào đó khá nhanh chóng. Nhưng 32   KB là số tiền phù hợp cho các ứng dụng được nhúng. Nó có xu hướng là RAM mà bạn có vấn đề với đầu tiên!

Ngoài ra, các trình biên dịch C++ cho các hệ thống nhúng thường tồi tệ hơn rất nhiều so với các trình biên dịch C. Tức là, chúng không ở đâu tốt như trình biên dịch C++ cho hệ điều hành máy tính để bàn thông thường (về mặt sản xuất mã máy hiệu quả cho nền tảng đích).

+0

Cảm ơn bạn đã phản hồi :) Chúng tôi sẽ xem liệu chúng tôi có mất nhiều không gian/RAM với C++/OOP hay không. – Klaus

2

Tải xuống IDE Arduino và 'xác minh' một số mã hiện có của bạn hoặc xem các bản phác thảo mẫu. Nó sẽ cho bạn biết có bao nhiêu byte là mã, mà sẽ cung cấp cho bạn một ý tưởng về bao nhiêu bạn có thể phù hợp với một thiết bị nhất định. Chọn một vài ví dụ ngẫu nhiên, ví dụ web server là 5816 byte và LCD hello world là 2616. Cả hai đều sử dụng thư viện bên ngoài.

+0

Tôi đã làm điều đó, nhưng ví dụ mặc định là tất cả khá nhỏ. Tôi tìm thấy một mã lớn hơn tại http://www.fisherinnovation.com/?p=fi-apartmentbot đã cho tôi một idead tốt hơn. Biên dịch, nó là khoảng 6 kB. – Klaus

2

Hãy thử tạo phiên bản ứng dụng đơn giản, tập trung vào tính năng có giá trị nhất trước tiên, sau đó bắt đầu thêm 'nội dung đẹp' và thú vị '. Theo dõi cách sử dụng byte được hiển thị trong Arduino IDE khi bạn xác minh mã của mình.

Như một chỉ dẫn thô, ứng dụng đầu tiên của tôi (LED flasher được điều khiển bởi một buttun đẩy) yêu cầu 1092 byte. Đó là khoảng 1K trong số 32k. Dấu chân khá nhỏ cho mã C++!

Điều khiến tôi lo lắng nhất là số lượng RAM giới hạn (1 Kb). Nếu ngăn xếp CPU mất một phần của nó, thì không còn nhiều để tạo ra bất kỳ cấu trúc dữ liệu nào.

Tôi chỉ có Arduino của mình trong 48 giờ, vì vậy vẫn còn rất nhiều để sử dụng nó một cách hiệu quả ;-) Nhưng thật thú vị khi sử dụng :).

+0

Cảm ơn bạn đã phản hồi và tư vấn :) Hãy vui vẻ với Arduino của bạn. – Klaus

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