2009-05-25 21 views
22

Các bạn, tôi muốn biết nếu float biến có thể được sử dụng trong chức năng sprintf().Sử dụng phao có sprintf() trong nhúng C

Giống như, nếu chúng ta viết:

sprintf(str,"adc_read = %d \n",adc_read); 

nơi adc_read là một biến số nguyên, nó sẽ lưu trữ các chuỗi

"adc_read = 1023 \n"

trong str (giả định rằng adc_read = 1023)

Làm thế nào tôi có thể sử dụng một biến float thay cho số nguyên?

+0

gì C-thư viện được bạn liên kết chống lại? – sybreon

+1

Lưu ý rằng bạn đang cố gắng định dạng gấp đôi. Với varargs trình biên dịch sẽ tự động thúc đẩy một giá trị float để tăng gấp đôi. – Richard

+3

"Đã nhúng", các bạn. Đó là chìa khóa. Nó không quan trọng những gì thư viện ưa thích của bạn shmancy làm trên máy tính của bạn với GB bộ nhớ :-) Embedded nền tảng thường có thương mại-offs hướng tới dấu chân bộ nhớ tối thiểu. – paxdiablo

Trả lời

40

Vì bạn đang sử dụng nền tảng nhúng, bạn hoàn toàn có thể không có đầy đủ các chức năng từ các chức năng kiểu printf().

Giả sử bạn có nổi ở tất cả (vẫn không nhất thiết là một trao cho các công cụ nhúng), bạn có thể bắt chước nó với một cái gì đó như:

char str[100]; 
float adc_read = 678.0123; 

char *tmpSign = (adc_read < 0) ? "-" : ""; 
float tmpVal = (adc_read < 0) ? -adc_read : adc_read; 

int tmpInt1 = tmpVal;     // Get the integer (678). 
float tmpFrac = tmpVal - tmpInt1;  // Get fraction (0.0123). 
int tmpInt2 = trunc(tmpFrac * 10000); // Turn into integer (123). 

// Print as parts, note that you need 0-padding for fractional bit. 

sprintf (str, "adc_read = %s%d.%04d\n", tmpSign, tmpInt1, tmpInt2); 

Bạn sẽ cần phải hạn chế bao nhiêu ký tự đến sau khi thập phân dựa trên các kích thước của các số nguyên của bạn.Ví dụ, với một số nguyên có dấu 16 bit, bạn bị giới hạn ở bốn chữ số (9,999 là số nguyên lớn nhất của mười chữ số có thể được biểu diễn). Tuy nhiên, có nhiều cách để xử lý điều này bằng cách xử lý thêm phần phân số, chuyển nó bằng bốn chữ số thập phân mỗi lần (và sử dụng/trừ phần nguyên) cho đến khi bạn có độ chính xác mong muốn.


Cập nhật:

Một điểm cuối cùng bạn nói rằng bạn đang sử dụng avr-gcc trong một phản ứng với một trong những câu trả lời khác. Tôi đã tìm thấy trang web sau đây có vẻ như mô tả những gì bạn cần làm để sử dụng %f trong các tuyên bố printf()here của mình.

Như tôi đã nghi ngờ ban đầu, bạn cần thực hiện thêm một số bước chân để có được hỗ trợ điểm nổi. Điều này là do công cụ nhúng hiếm khi cần điểm nổi (ít nhất là không có thứ gì tôi từng làm). Nó liên quan đến việc thiết lập các tham số bổ sung trong makefile của bạn và liên kết với các thư viện phụ.

Tuy nhiên, điều đó có khả năng tăng kích thước mã của bạn khá nhiều do cần phải xử lý các định dạng đầu ra chung. Nếu bạn có thể hạn chế đầu ra float của bạn đến 4 chữ số thập phân hoặc ít hơn, tôi khuyên bạn nên chuyển mã của tôi thành một hàm và chỉ sử dụng nó - nó có khả năng chiếm ít chỗ hơn.

Trong trường hợp liên kết bao giờ biến mất, những gì bạn phải làm là đảm bảo rằng lệnh gcc của bạn có "-Wl,-u,vfprintf -lprintf_flt -lm" Điều này được chuyển tới:.

  • lực vfprintf được ban đầu không xác định (do đó mối liên kết có để giải quyết nó).
  • xác định nổi thư viện điểm printf() để tìm kiếm.
  • định thư viện toán học để tìm kiếm.
+0

đó là một thủ thuật rất hay, tôi sẽ cố gắng nó ra thanx – aditya

+0

nó đem lại cho lỗi biên dịch lỗi: dự kiến ​​biểu trước 'int' trong mã trên trong dòng 5 – aditya

+0

Xin lỗi, quá nhiều Java. Xem cập nhật. – paxdiablo

0

sử dụng %f modifier:

sprintf (str, "adc_read = %f\n", adc_read); 

Ví dụ:

#include <stdio.h> 

int main (void) 
{ 
    float x = 2.5; 
    char y[200]; 

    sprintf(y, "x = %f\n", x); 
    printf(y); 
    return 0; 
} 

sản lượng này:

x = 2.500000

+1

Tôi đã làm, nhưng nó không hoạt động \t nó in a? ký tự thay vì chuỗi – aditya

-2

Có, sử dụng% f

+0

Tôi đã làm, nhưng nó không hoạt động – aditya

+1

nó in a? ký tự thay vì chuỗi. – aditya

+0

Làm thế nào nó không hoạt động? Sản lượng sai? – rein

0

Có tất nhiên, có không có gì đặc biệt với phao nổi. Bạn có thể sử dụng các chuỗi định dạng như bạn sử dụng trong printf() cho các float và các kiểu dữ liệu khác.

EDIT tôi đã cố gắng mẫu này mã:

float x = 0.61; 
char buf[10]; 
sprintf(buf, "Test=%.2f", x); 
printf(buf); 

Output là: Test = 0,61

+0

Tôi đã làm, nhưng nó không hoạt động \t nó in a? ký tự thay vì chuỗi – aditya

+0

Xem chỉnh sửa cho mã mẫu của tôi .. Tôi có cảm giác rằng bộ đệm "str" ​​của bạn quá nhỏ .. hãy thử sử dụng thứ gì đó tương tự% .2f để đặt độ chính xác. – Naveen

+0

kích thước của bộ đệm của tôi là 100 trên thực tế, tôi đang in trên cổng nối tiếp, vì vậy tôi nghĩ rằng sự cố đang truyền biến nổi trên UART – aditya

2

Có bạn có thể. Tuy nhiên, nó phụ thuộc vào thư viện C mà bạn đang liên kết chống lại và bạn cần phải nhận thức được hậu quả.

Vì bạn đang lập trình cho các ứng dụng nhúng, nhận ra rằng hỗ trợ dấu phẩy động được mô phỏng cho rất nhiều kiến ​​trúc nhúng. Việc biên dịch trong hỗ trợ dấu chấm động này sẽ kết thúc việc tăng kích thước tệp thực thi của bạn một cách đáng kể.

+0

Tôi đang sử dụng avr-gcc – aditya

1

Đừng mong đợi sprintf (hoặc bất kỳ chức năng nào khác có vararg) để tự động truyền bất kỳ thứ gì. Trình biên dịch không cố gắng đọc chuỗi định dạng và thực hiện việc truyền cho bạn; tại thời điểm chạy, sprintf không có sẵn siêu thông tin để xác định những gì có trong ngăn xếp; nó chỉ bật các byte và diễn giải chúng như được đưa ra bởi chuỗi định dạng. sprintf (myvar, "% 0", 0); ngay lập tức segfaults.

Vì vậy: Chuỗi định dạng và đối số khác phải khớp với nhau!

0

Có và không. Mặc dù những gì một số trả lời khác đã nói, trình biên dịch C cần thiết để thực hiện chuyển đổi cho sprintf(), và tất cả các chức năng variadic khác, như sau:

  • char =>int
  • short =>int
  • float =>double

(và các biến thể đã ký/chưa ký của ab các loại tích phân ove)

Nó thực hiện điều này một cách chính xác vì sprintf() (và các chức năng khác của gia đình print()) sẽ không sử dụng được nếu không có. (Tất nhiên, they're pretty unusable as it is.)

Nhưng bạn không thể chịu bất kỳ chuyển đổi nào khác và mã của bạn sẽ có hành vi không xác định - đã đọc: lỗi! - nếu bạn làm điều đó.

+1

Trình biên dịch được yêu cầu để thực hiện _conversions_. Một _cast_ được yêu cầu một cách rõ ràng bởi lập trình viên. – mlp

+0

nhận xét công bằng. sửa lỗi hiện tại – dcw

+1

"Không sử dụng được" là một từ khá mạnh. Các printf() gia đình là khá có thể sử dụng, nhưng nó không phải là hoàn hảo. Nó có lỗ hổng an toàn loại rõ ràng, nhưng trình biên dịch có thể dễ dàng kiểm tra các loại đối số bạn đang truyền trong 99% trường hợp sử dụng và cung cấp cho bạn cảnh báo/lỗi (xem gcc's -Wformat et al). –

0

Tìm tài liệu cho sprintf cho nền tảng của bạn. Thường là% f hoặc% e. Nơi duy nhất bạn sẽ tìm thấy một câu trả lời nhất định là tài liệu ... nếu tất cả những gì bạn có thể làm thì bạn có thể liên lạc với nhà cung cấp.

Nền tảng là gì? Ai đó có thể đã biết tài liệu ở đâu ... :)

+0

vi điều khiển Atmega128 Trình biên dịch là avr-gcc. Cảm ơn bạn đã trả lời, nhưng câu trả lời được đưa ra bởi Pax đã làm việc hoàn hảo. – aditya

0

Đừng làm điều này; các số nguyên trong C/C++ luôn được làm tròn xuống do đó không cần sử dụng chức năng sàn.

char str[100]; 
int d1 = value; 

Tốt hơn để sử dụng

int d1 = (int)(floor(value)); 

Sau đó, bạn sẽ không nhận được làm tròn lên của phần số nguyên (68,9999999999999999 trở 69.00 ..). 68.09999847 thay vì 68,1 rất khó tránh - bất kỳ định dạng điểm nổi nào có độ chính xác giới hạn.

3

Không phải là một cái gì đó như thế này thực sự dễ dàng hơn:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

char str[10]; 
float adc_read = 678.0123; 

dtostrf(adc_read, 3, 4, temp); 
sprintf(str,"adc_read = %10s \n", temp); 
printf(temp); 
+0

có nó đã làm việc tuyệt vời cho tôi sau nhiều giờ tìm kiếm, nhờ –

+0

Nó dễ dàng hơn, nhưng nó không hoạt động nếu bạn không thể nhúng stdlib vì bạn đang nhắm mục tiêu một vi điều khiển nhỏ. – Funkodebat

0

% g thể làm điều này:

#include <stdio.h> 
int main() { 
    float w = 234.567; 
    char x[__SIZEOF_FLOAT__]; 
    sprintf(x, "%g", w); 
    puts(x); 
} 
Các vấn đề liên quan