Используя плавания с sprintf () во встроенном C

Для чего это стоит, NHibernate: Оптимизация запросов с помощью проекций помогли мне в основном с этой же проблемой.

26
задан starblue 6 June 2009 в 08:28
поделиться

9 ответов

Since you're on an embedded platform, it's quite possible that you don't have the full range of capabilities from the printf()-style functions.

Assuming you have floats at all (still not necessarily a given for embedded stuff), you can emulate it with something like:

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);

You'll need to restrict how many characters come after the decimal based on the sizes of your integers. For example, with a 16-bit signed integer, you're limited to four digits (9,999 is the largest power-of-ten-minus-one that can be represented).

However, there are ways to handle this by further processing the fractional part, shifting it by four decimal digits each time (and using/subtracting the integer part) until you have the precision you desire.


Update:

One final point you mentioned that you were using avr-gcc in a response to one of the other answers. I found the following web page that seems to describe what you need to do to use %f in your printf() statements here.

As I originally suspected, you need to do some extra legwork to get floating point support. This is because embedded stuff rarely needs floating point (at least none of the stuff I've ever done). It involves setting extra parameters in your makefile and linking with extra libraries.

However, that's likely to increase your code size quite a bit due to the need to handle general output formats. If you can restrict your float outputs to 4 decimal places or less, I'd suggest turning my code into a function and just using that - it's likely to take up far less room.

In case that link ever disappears, what you have to do is ensure that your gcc command has "-Wl,-u,vfprintf -lprintf_flt -lm". This translates to:

  • force vfprintf to be initially undefined (so that the linker has to resolve it).
  • specify the floating point printf() library for searching.
  • specify the math library for searching.
47
ответ дан 28 November 2019 в 07:04
поделиться

Yes you can. However, it depends on the C-library that you are linking against and you need to be aware of the consequences.

Since you are programming for embedded applications, realise that floating-point support is emulated for a lot of embedded architectures. Compiling in this floating-point support will end up increasing the size of your executable significantly.

2
ответ дан 28 November 2019 в 07:04
поделиться

Не ожидайте, что sprintf (или любая другая функция с varargs) будет автоматически приводить что-либо. Компилятор не пытается прочитать строку формата и выполнить приведение за вас; во время выполнения sprintf не имеет доступной метаинформации для определения того, что находится в стеке; он просто выталкивает байты и интерпретирует их, как указано в строке формата. sprintf (myvar, "% 0", 0); немедленно segfaults.

Итак: строки формата и другие аргументы должны совпадать!

1
ответ дан 28 November 2019 в 07:04
поделиться

Да, конечно, с поплавками нет ничего особенного. Вы можете использовать строки формата, которые вы используете в printf () для чисел с плавающей запятой и любых других типов данных.

EDIT Я попробовал этот пример кода:

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

Результат был: Test = 0,61

0
ответ дан 28 November 2019 в 07:04
поделиться

используйте модификатор % f :

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

Например:

#include <stdio.h>

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

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

Результат:

x = 2.500000

0
ответ дан 28 November 2019 в 07:04
поделиться

Yes, and no. Despite what some other replies have said, the C compiler is required to perform conversions for sprintf(), and all other variadic functions, as follows:

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

(and signed/unsigned variants of the above integral types)

It does this precisely because sprintf() (and the other print()-family functions) would be unusable without it. (Of course, they're pretty unusable as it is.)

But you cannot assume any other conversions, and your code will have undefined behaviour - read: crash! - if you do it.

0
ответ дан 28 November 2019 в 07:04
поделиться

Поищите в документации sprintf для вашей платформы. Обычно это% f или% e. Единственное место, где вы найдете определенный ответ, - это документация ... если она недокументирована, все, что вы можете сделать, - это связаться с поставщиком.

Что это за платформа? Кто-то может уже знать, где находятся документы ... :)

0
ответ дан 28 November 2019 в 07:04
поделиться

Да, используйте% f

-2
ответ дан 28 November 2019 в 07:04
поделиться

Не делайте этого; целые числа в Си/Си++ всегда округляются вниз, поэтому нет необходимости использовать функцию floor.

char str[100]; 
int d1 = value;

Лучше использовать

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

Тогда округление целочисленной части не получится (68.99999999999999 становится 69.00...). 68.09999847 вместо 68.1 трудно избежать - любой формат с плавающей точкой имеет ограниченную точность.

.
0
ответ дан 28 November 2019 в 07:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: