prosource

내장된 C에 sprintf()가 있는 Float 사용

probook 2023. 10. 25. 23:24
반응형

내장된 C에 sprintf()가 있는 Float 사용

얘들아, 난 알고 싶습니다.float변수를 사용할 수 있습니다.sprintf()기능.

예를 들면 다음과 같이 적습니다.

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

어디에adc_read는 정수 변수이며 문자열을 저장합니다.

"adc_read = 1023 \n"

인에str(라고 assuming합니다.adc_read = 1023)

정수 대신 부동 변수를 사용하려면 어떻게 해야 합니까?

임베디드 플랫폼을 사용하고 있기 때문에 다양한 기능을 제공하지 못할 가능성이 높습니다.printf()스타일 함수.

플로트가 전혀 없다고 가정할 때(내장된 것에 대해 반드시 주어진 것은 아님) 다음과 같은 방법으로 플로트를 에뮬레이트할 수 있습니다.

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비트 부호 정수의 경우 4자리로 제한됩니다(9,999는 표현할 수 있는 가장 큰 10분의 1 전력).

그러나 원하는 정밀도를 갖출 때까지 분수 부분을 더 처리하고, 매번 소수점 네 자리씩 이동(그리고 정수 부분을 사용/ 뺄셈)하여 이를 처리하는 방법이 있습니다.


업데이트:

당신이 말한 마지막 포인트는 당신이 사용하고 있던avr-gcc다른 답변들 중 하나에 대한 답변으로.나는 당신이 사용하기 위해 무엇을 해야 하는지 설명해주는 다음 웹페이지를 찾았습니다.%f당신의printf()여기 진술서들.

처음에 예상했던 것처럼, 부동 소수점 지원을 받으려면 추가적인 다리 작업을 해야 합니다.이것은 내장된 것들이 거의 부동 소수점이 필요하지 않기 때문입니다. (적어도 제가 해본 것들 중 어느 것도 필요하지 않습니다.여기에는 makefile에 추가 파라미터를 설정하고 추가 라이브러리와 연결하는 작업이 포함됩니다.

그러나 일반 출력 형식을 처리해야 하기 때문에 코드 크기가 상당히 증가할 가능성이 있습니다.플로트 출력을 소수점 4자리 이하로 제한할 수 있다면 제 코드를 함수로 변환하여 사용하는 것이 좋습니다. 공간을 훨씬 적게 차지할 수 있기 때문입니다.

링크가 사라질 경우, 당신이 해야 할 일은 당신의 gcc 명령이"-Wl,-u,vfprintf -lprintf_flt -lm과 같습니다." 이 뜻은 다음과 같습니다.

  • vfprintf를 초기에 정의하지 않도록 강제합니다(링크러에서 해결해야 함).
  • 부동 소수점 지정printf()검색용 라이브러리
  • 검색할 수학 라이브러리를 지정합니다.

이와 같은 일은 정말 쉽지 않습니까?

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

네, 가능합니다.그러나 링크하는 C 라이브러리에 따라 다르므로 결과에 대해 인지해야 합니다.

임베디드 응용프로그램을 프로그래밍하는 경우, 부동 소수점 지원은 많은 임베디드 아키텍처에 대해 에뮬레이트된다는 사실을 깨달아야 합니다.이 부동 소수점 지원에서 컴파일하면 실행 파일의 크기가 크게 증가하게 됩니다.

네, 플로트는 특별한 게 없습니다.frintf()에서 플로트 및 기타 데이터 유형에 사용하는 것처럼 형식 문자열을 사용할 수 있습니다.

편집 다음 샘플 코드를 시도했습니다.

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

출력: Test=0.61

sprintf(또는 varrags가 있는 다른 기능)가 어떤 것도 자동으로 주조하지 않도록 합니다.컴파일러는 형식 문자열을 읽고 캐스트를 수행하려고 하지 않습니다. 런타임에 sprintf는 스택에 무엇이 있는지 확인할 수 있는 메타 정보가 없습니다. 바이트만 팝하고 형식 문자열이 주는 대로 해석합니다. sprintf(myvar, "%0", 0); 즉시 segfaults.

따라서: 형식 문자열과 다른 인수가 일치해야 합니다!

을 합니다.%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

많은 임베디드 시스템에는 플로트를 처리하지 않는 제한된 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 );
}

플랫폼에 대한 sprintf는 설명서에서 확인할 수 있습니다.보통 %e에 해당합니다.확실한 답을 찾을 수 있는 유일한 곳은 문서...만약 그것이 문서화되지 않았다면 당신이 할 수 있는 모든 것은 공급업체에 연락하는 것입니다.

몇 번 승강장입니까?누군가는 이미 문서가 어디에 있는지 알고 있을 수도 있습니다. :)

한마디로 이야기할 수 없군요.몇몇 다른 답변들에도 불구하고, C 컴파일러는 다음에 대한 변환들을 수행하도록 요구됩니다.sprintf(), 기타 모든 가변 함수는 다음과 같습니다.

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

(및 위의 적분형의 부호/부호 변형)

이것은 정확히 이것을 합니다 왜냐하면sprintf()(그리고 다른 하나print()-가족 기능)이 없으면 사용할 수 없을 겁니다. (물론 지금 상태로는 거의 사용할 수 없습니다.)

그러나 다른 변환을 가정할 수 없으며 코드에 정의되지 않은 동작이 발생합니다(읽기: crash! - crash!).

%g이(가) 수행할 수 있는 작업:

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

위의 팍스디아블로와 비슷합니다.더 넓은 앱에 삽입된 이 코드는 STM32 NEUCO-F446RE와 잘 작동합니다.

#include <stdio.h>
#include <math.h>
#include <string.h>
void IntegFract(char *pcIntegStr, char *pcFractStr, double dbValue, int iPrecis);

main()
{
   char acIntegStr[9], acFractStr[9], char counter_buff[30];
   double seconds_passed = 123.0567;
   IntegFract(acIntegStr, acFractStr, seconds_passed, 3);
   sprintf(counter_buff, "Time: %s.%s Sec", acIntegStr, acFractStr);
}

void IntegFract(char *pcIntegStr, char *pcFractStr, double dbValue, int 
iPrecis)
{
    int iIntegValue = dbValue;
    int iFractValue = (dbValue - iIntegValue) * pow(10, iPrecis);
    itoa(iIntegValue, pcIntegStr, 10);
    itoa(iFractValue, pcFractStr, 10);
    size_t length = strlen(pcFractStr);
    char acTemp[9] = "";
    while (length < iPrecis)
    {
        strcat(acTemp, "0");
        length++;
    }
    strcat(acTemp, pcFractStr);
    strcpy(pcFractStr, acTemp);
}

counter_buff에는 123.056이 포함됩니다.

그러면 안 됩니다. C/C++의 정수는 항상 반올림되므로 플로어 기능을 사용할 필요가 없습니다.

char str[100]; 
int d1 = value;

사용하기 좋음

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

그러면 정수 부분을 반올림할 수 없습니다(68.99999999999999999969...). 68.1이 아닌 68.09999847은 피하기 어렵습니다. 부동 소수점 형식은 정밀도가 제한됩니다.

예, %f 사용

언급URL : https://stackoverflow.com/questions/905928/using-floats-with-sprintf-in-embedded-c

반응형