programing

printf에서 선행 0을 숨기는 방법

megabox 2023. 9. 26. 22:15
반응형

printf에서 선행 0을 숨기는 방법

다음과 같은 결과0.23. 간단히 출력하려면 어떻게 해야 합니까?.23?

printf( "%8.2f" , .23 );

C 표준에는 다음과 같이 나와 있습니다.f그리고.F부동 소수점 형식 지정자:

소수점 문자가 나타나면 그 앞에 한 자리 이상의 숫자가 나타납니다.

소수점 앞에 0이 나타나지 않으려면 사용과 같은 작업을 해야 할 것 같습니다.snprintf()숫자를 문자열로 포맷하고 제거합니다.0형식이 지정된 문자열이 "0"으로 시작하는 경우(그리고 "-0"도 마찬가지).그러면 형식화된 문자열을 실제 출력으로 전달합니다.아니면 그런 비슷한 것.

를 사용해서만 할 수 있는 것은 아닙니다.printf. 에 대한 설명서printf다음과 같이 말합니다.

f  - "double" argument is output in conventional form, i.e.
     [-]mmmm.nnnnnn
     The default number of digits after the decimal point is six,
     but this can be changed with a precision field. If a decimal point
     appears, at least one digit appears before it. The "double" value is
     rounded to the correct number of decimal places.

소수점이 나타나면앞에 적어도 하나의 숫자가 나타납니다.

따라서 자신의 서식을 직접 코드화해야 할 것 같습니다.

필요한 정확도를 가진 정수로 변환하기만 하면 됩니다.

double value = .12345678901; // input
int accuracy = 1000; // 3 digit after dot
printf(".%03d\n", (int)(value * accuracy) );

출력:

.123

페이스트빈의 예제 소스

double f = 0.23;

assert(f < 0.995 && f >= 0);  
printf(".%02u\n" , (unsigned)((f + 0.005) * 100));
#include <stdio.h>

static void printNoLeadingZeros(double theValue)
{
   char buffer[255] = { '\0' };

   sprintf(buffer, "%.2f", theValue);

   printf("%s\n", buffer + (buffer[0] == '0'));
}

int main()
{
   double values[] = { 0.23, .23, 1.23, 01.23, 001.23, 101.23 };
   int n           = sizeof(values) / sizeof(values[0]);
   int i           = 0;

   while(i < n)
      printNoLeadingZeros(values[i++]);

   return(0);
}

스탠다드 C 도서관에서는 이것을 제공하지 않기 때문에 직접 작성하셔야 합니다.이것은 드문 일회성 요구사항이 아닙니다.후행 0을 다듬고 수천 개의 구분자를 추가하려면 조만간 유사한 함수를 작성해야 합니다.따라서 원하는 출력 바이트를 얻을 수 있을 뿐만 아니라 강력한 라이브러리를 작성하는 방법을 보다 일반적으로 설명하는 것이 좋습니다.이 작업을 수행할 때는 다음 사항을 유의해야 합니다.

  1. 어떻게 부를지 생각해 보세요.이런 것은 한 번 쓰고 백만 번 전화하는 것이니, 가능한 한 쉽게 전화를 걸도록 하세요.

  2. 그런 다음 당신이 생각할 수 있는 모든 대안을 연습하는 테스트 스위트를 만듭니다.

  3. 그렇게 하는 동안 문제를 더 이상 풀어서 다시는 그 문제로 돌아가지 않도록 하세요(예: 폭, 정밀도를 하드코드하지 말고 계속해서 리딩 플러스, e-포맷 등을 위한 버전을 만들어 보세요).

  4. 스레드를 사용하지 않더라도 스레드에서 안전하게 사용할 수 있습니다(실제로 포인트 3의 특정 경우).

거꾸로 작업하기:스레드 안전을 위해서는 스택에 저장소를 할당해야 하며, 이 작업은 호출자가 수행해야 합니다.이것은 예쁘지도 않고 재미도 없지만 그냥 익숙해지세요.C 방식입니다.형식은 너비, 정밀도, 일부 플래그 및 변환 유형(f, e, g)을 가질 수 있습니다.폭과 정밀도 파라미터를 만들어 보겠습니다.퍼블릭 API를 완전히 파라미터화하는 것보다는 함수 이름에 어떤 플래그와 변환 유형을 사용하는지를 나타내는 엔트리 포인트를 여러 개 가지고 있겠습니다.

불만은 버퍼를 기능에 전달할 때 기능의 크기를 알아야 한다는 것입니다.하지만 별도의 파라미터를 만들면 1) 발신자가 작성해야 하고 2) 발신자가 틀릴 수 있기 때문에 불편합니다.그래서 저의 개인 스타일은 버퍼를 포인터가 아닌 문자 배열로 가정하고 ()의 크기를 사용하여 크기를 취하는 함수의 더 자세한 버전으로 전달하는 마스킹 매크로를 만드는 것입니다.

여기 제가 생각해낼 수 있는 가장 간단한 방법과 시험 사례가 있습니다.

(참고 COUNT()는 배열의 요소 수를 얻기 위해 수십 년 동안 매주 사용해 온 매크로입니다.표준 C, 이런 것이 있어야 합니다.)

(참고로 저는 여기서 "헝가리어 표기법"의 방언을 사용합니다."d"는 두 배입니다."a"는 "array of"입니다. "sz"는 NUL 종단 문자열 버퍼이고 "psz"는 1을 가리키는 포인터입니다.이 둘의 차이점은 "sz"가 COUNT() 또는 크기가 ()인 경우 배열 크기를 얻을 수 있는 반면 "psz"는 그렇지 않다는 것입니다."i"는 정수이고 특정 변수 "i"는 루프에 사용됩니다.

double ad[] = { 0.0, 1.0, 2.2, 0.3, 0.45, 0.666, 888.99,
                -1.0, -2.2, -0.3, -0.45, -0.666, -888.99 };
char   szBuf[20];

for ( int i = 0; i < COUNT( ad ); i++ )
    printf( "%s\n", NoLeadingZeroF( 4, 2, ad[i], szBuf ) );

for ( int i = 0; i < COUNT( ad ); i++ )
    printf( "%s\n", NoLeadingZeroPlusF( 4, 2, ad[i], szBuf ) );

이제 "f" 버전과 "+f" 버전이 매우 유사해 보이므로 둘 다 내부 함수를 부르도록 합시다.버퍼크기를 취하는 함수들과 그것을 스스로 계산하는 매크로들이 있습니다. (병렬함수는 e, g 형식의 경우에도 쓰입니다.)

char* NoLeadingZeroFN( int iWidth, int iPrecision, double d, char* szBuf, int iBufLen ) {
  return NoLeadingZeroFmtN( "%*.*f", iWidth, iPrecision, d, szBuf, iBufLen );
}

char* NoLeadingZeroPlusFN( int iWidth, int iPrecision, double d, char* szBuf, int iBufLen ) {
  return NoLeadingZeroFmtN( "%+*.*f", iWidth, iPrecision, d, szBuf, iBufLen );
}


#define NoLeadingZeroF( width, precision, number, buf ) \
        NoLeadingZeroFN( ( width ), (precision ), ( number ), ( buf ), sizeof( buf ) ) 

#define NoLeadingZeroPlusF( width, precision, number, buf ) \
        NoLeadingZeroPlusFN( ( width ), (precision ), ( number ), ( buf ), sizeof( buf ) ) 

마지막으로 일을 하는 (내부) 기능.snprintf()는 Windows에서는 미리 지정된 밑줄이 필요하지만 Unix에서는 필요하지 않습니다.

char* NoLeadingZeroFmtN( char* szFmt, int iWidth, int iPrecision, double d, char* szBuf, int iBufLen ) {

#ifdef WIN32
  _snprintf( szBuf, iBufLen - 1, szFmt, iWidth, iPrecision, d );
#else
  snprintf( szBuf, iBufLen - 1, szFmt, iWidth, iPrecision, d );
#endif

  // Some snprintf()'s do not promise to NUL-terminate the string, so do it ourselves.
  szBuf[ iBufLen - 1 ] = '\0';

  // _snprintf() returns the length actually produced, IF the buffer is big enough.
  // But we don't know it was, so measure what we actually got.
  char* pcTerminator = strchr( szBuf, '\0' );

  for ( char* pcBuf = szBuf; *pcBuf && *pcBuf != '.'; pcBuf++ )
      if ( *pcBuf == '0' ) {
          memmove( pcBuf, pcBuf + 1, pcTerminator - pcBuf );
          break;
      }

  return szBuf;
}

출력은 다음과 같습니다.

.00
1.00
2.20
.30
.45
.67
888.99
-1.00
-2.20
-.30
-.45
-.67
-888.99
+.00
+1.00
+2.20
+.30
+.45
+.67
+888.99
-1.00
-2.20
-.30
-.45
-.67
-888.99

추가 테스트를 통해 기능이 너무 작은 버퍼에서 작동하는지 확인해야 합니다.

쉬운 해결책이 없어 보입니다.저는 아마 아래와 같은 코드를 사용할 것입니다.가장 빠른 방법은 아니지만 다양한 형식으로 작동해야 합니다.문자 수와 점의 위치도 보존합니다.

#include <stdio.h>

void fixprint(char *s)
{
        size_t i;
        i = 1;
        while (s[i]=='0' || s[i]==' ' || s[i]=='+' || s[i]=='-') {
                if (s[i]=='0') s[i]=' ';
                i++;
        }
}

int main()
{
        float x = .23;
        char s[14];
        sprintf(s,"% 8.2f",x);
        fixprint(s);
        printf("%s\n",s);
}

작업은 하여 수행할 수 .printf()그럼 어떻게 완벽하게 해낼 수 있을까요?

이것이 제 해결책입니다.

sprintf()=>=>=float.string.

    #include <stdio.h>
    #include <string.h>
    int main()
    {
    char result[50];
    float num = 0.23;
    sprintf(result, "%.2f", num);

    char *str = result;
    int n = strspn(str, "0" );
    printf("Trimmed string is %s ", &str[n]);

    return 0;
}

산출량

Trimmed string is .23

언급URL : https://stackoverflow.com/questions/2595738/how-to-hide-leading-zero-in-printf

반응형