Подтвердить что ты не робот

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

Ребята, я хочу знать, могут ли переменные float использоваться в sprintf().

Например, если мы пишем:

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

где adc_read - целочисленная переменная, она сохранит строку

"adc_read = 1023 \n"

в str (предполагая, что adc_read = 1023)

Как я могу использовать переменную float вместо целого?

4b9b3361

Ответ 1

Поскольку вы работаете на встроенной платформе, вполне возможно, что вы не обладаете полным спектром возможностей функций printf() -style.

Предполагая, что у вас вообще есть плавающие объекты (все еще не обязательно заданные для встроенных объектов), вы можете эмулировать их примерно так:

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

Вам нужно будет ограничить количество символов после десятичного знака в зависимости от размеров ваших целых чисел. Например, с 16-разрядным целым числом со знаком вы ограничены четырьмя цифрами (9 999 - это наибольшая степень десяти-минус единицы, которую можно представить).

Однако есть способы справиться с этим, дополнительно обрабатывая дробную часть, каждый раз сдвигая ее на четыре десятичных знака (и используя/вычитая целую часть), пока вы не получите желаемую точность.


Обновить:

В заключение вы упомянули, что вы использовали avr-gcc в ответе на один из других ответов. Я нашел следующую веб-страницу, которая, кажется, описывает, что вам нужно сделать, чтобы использовать %f в ваших выражениях printf() здесь.

Как я изначально подозревал, вам нужно проделать дополнительную работу, чтобы получить поддержку с плавающей запятой. Это потому, что встроенному материалу редко нужна плавающая точка (по крайней мере, ни один из того, что я когда-либо делал). Он включает в себя установку дополнительных параметров в вашем make файле и связывание с дополнительными библиотеками.

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

В случае, если эта ссылка когда-либо исчезнет, вам нужно убедиться, что ваша команда gcc имеет "-Wl,-u,vfprintf -lprintf_flt -lm ". Это переводится как:

  • заставить vfprintf быть изначально неопределенным (чтобы компоновщик должен был его разрешить).
  • указать библиотеку printf() с плавающей точкой для поиска.
  • указать математическую библиотеку для поиска.

Ответ 2

Разве это не так проще:

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

Ответ 3

Да, вы можете. Однако это зависит от C-библиотеки, с которой вы связываетесь, и вам нужно знать о последствиях.

Поскольку вы программируете для встроенных приложений, понимайте, что поддержка с плавающей запятой эмулируется для множества встроенных архитектур. Компиляция в этой поддержке с плавающей запятой приведет к значительному увеличению размера вашего исполняемого файла.

Ответ 4

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

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

Ответ 5

используйте модификатор %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

Ответ 6

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

ИЗМЕНИТЬ Я попробовал этот пример кода:

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

Выход был: Test = 0.61

Ответ 7

Да, и нет. Несмотря на то, что говорили некоторые другие ответы, компилятор C требуется для выполнения преобразований для sprintf() и всех других вариационных функций следующим образом:

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

(и подписанные/неподписанные варианты указанных интегральных типов)

Он делает это именно потому, что sprintf() (и другие print() -семейные функции) без него будет непригодным. (Конечно, они довольно непригодны для использования.

Но вы не можете предполагать никаких других преобразований, и ваш код будет иметь поведение undefined - читать: crash! - если вы это сделаете.

Ответ 8

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

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

Ответ 9

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

char str[100]; 
int d1 = value;

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

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

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

Ответ 10

% g может сделать это:

#include <stdio.h>
int main() {
  float w = 234.567;
  char x[__SIZEOF_FLOAT__];
  sprintf(x, "%g", w);
  puts(x);
}

Ответ 11

Многие встроенные системы имеют ограниченную функцию snprintf, которая не обрабатывает операции с плавающей точкой. Я написал это, и это довольно эффективно. Я решил использовать 64-разрядные целые числа без знака, чтобы иметь возможность обрабатывать большие числа с плавающей запятой, поэтому не стесняйтесь сокращать их до 16-разрядных или любых других потребностей с ограниченными ресурсами.

#include <stdio.h>   // for uint64_t support.


int  snprintf_fp( char destination[], size_t available_chars, int decimal_digits,
                  char tail[], float source_number )
{
    int   chars_used  = 0;    // This will be returned.


    if ( available_chars > 0 )
    {
        // Handle a negative sign.
        if ( source_number < 0 )
        {
            // Make it positive
            source_number = 0 - source_number;
            destination[ 0 ] = '-';
            ++chars_used;
        }

        // Handle rounding
        uint64_t zeros = 1;
        for ( int i = decimal_digits; i > 0; --i )
            zeros *= 10;

        uint64_t source_num = (uint64_t)( ( source_number * (float)zeros ) + 0.5f );

        // Determine sliding divider max position.
        uint64_t  div_amount = zeros;       // Give it a head start
        while ( ( div_amount * 10 ) <= source_num )
            div_amount *= 10;

        // Process the digits
        while ( div_amount > 0 )
        {
            uint64_t whole_number = source_num / div_amount;
            if ( chars_used < (int)available_chars )
            {
                destination[ chars_used ] = '0' + (char)whole_number;
                ++chars_used;

                if ( ( div_amount == zeros ) && ( zeros > 1 ) )
                {
                    destination[ chars_used ] = '.';
                    ++chars_used;
                }
            }
            source_num -= ( whole_number * div_amount );
            div_amount /= 10;
        }


        // Store the zero.
        destination[ chars_used ] = 0;

        // See if a tail was specified.
        size_t tail_len = strlen( tail );

        if ( ( tail_len > 0 ) && ( tail_len + chars_used < available_chars ) )
        {
            for ( size_t i = 0; i <= tail_len; ++i )
                destination[ chars_used + i ] = tail[ i ];
            chars_used += tail_len;
        }
    }

    return chars_used;
}

main()
{
    #define TEMP_BUFFER_SIZE 30
    char temp_buffer[ TEMP_BUFFER_SIZE ];
    char  degrees_c[] = { (char)248, 'C', 0 };
    float  float_temperature = 26.845f;

    int len = snprintf_fp( temp_buffer, TEMP_BUFFER_SIZE, 2, degrees_c, float_temperature );
}

Ответ 12

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