【问题标题】:C printf: Is there a way to add text after variable and before spacing?C printf:有没有办法在变量之后和间距之前添加文本?
【发布时间】:2020-10-09 19:36:14
【问题描述】:

我想使用 printf 创建这样的输出:

Name          Available         Required
------------- ----------------- ---------------
Something     10.1 GiB          2.3 GiB

但是使用内置的间距机制不允许添加测量文本(即 Gb)after 变量,before 空间。问题是该文本需要包含在间距中。我试过了

"%-12.1f GiB"

在空格后面加上“GiB”。

【问题讨论】:

  • 请准确显示您的代码输出的内容,而不是描述结果。同时显示生成结果的确切代码。
  • 这个右对齐确实更容易;否则,您需要 sprintf 组件字符串并使用 %s 和宽度说明符
  • @EugeneSh 。看起来很清楚:数字(10.12.3 和单位 Gb 一起放在一个填充到 12 的字符串中。

标签: c printf


【解决方案1】:

printf 函数不会一次性完成此操作。使用中间字符串。

double gigabytes_avail;
char buf[64];
snprintf(buf, sizeof(buf), "%.1f GB", gigabytes_avail);

printf("%-12s", buf);

如果您使用 Visual Studio 及其编译器,您可以考虑使用 sprintf_s() 而不是 snprintf()。它们不是同一个功能,但sprintf_s()适合这里。

或者,您可以自己进行填充,因为 printf 返回写入的字符数……

int column_width = 15;
double gigabytes_avail;
// Does not handle errors, printf may return -1.
int r = printf("%.1f GB", gigabytes_avail);
for (; r < column_width; r++) {
    putchar(' ');
}

请注意,千兆字节的符号是 GB,而不是 Gb。千兆就是千兆。

【讨论】:

  • +1,但据我所知,OP从未提及bytes...它可以以千兆位显示网络容量...
  • 千兆也不是千兆。
  • 为了处理好所有的double"%.1f GB",建议buf[(1 /* sign */ + DBL_MAX_10_EXP + 1 /* '.' */ + 1 /* frac */) + 3 + 1]或者一般是315左右。当然OP还有其他问题应该gigabytes_avail过分。
  • 根据我的数学计算,当您在太阳中为每个原​​子提供 1GB 可用空间时,64 字节会溢出。
  • 关于有效的gigabytes_avail 是正确的,更多的是关注导致其他问题的错误值,并作为如何处理所有double 的示例。
【解决方案2】:

printf 返回打印的字符数。
使用一个printf 中的值填充后续的printf

#include <stdio.h>

int main ( void) {

    printf ( "Name          Available         Required\n");
    printf ( "------------- ----------------- ---------------\n");

    for ( int out = 0; out < 20; out += 3) {
        printf ( "%-15s", "Something");
        int span = printf ( "%5.1f Gb", out * 10.1);
        printf ( "%*.1f Gb\n", 22 - span, out * 2.3);
    }

    return 0;
}  

输出:

Name          Available         Required
------------- ----------------- ---------------
Something        0.0 Gb           0.0 Gb
Something       30.3 Gb           6.9 Gb
Something       60.6 Gb          13.8 Gb
Something       90.9 Gb          20.7 Gb
Something      121.2 Gb          27.6 Gb
Something      151.5 Gb          34.5 Gb
Something      181.8 Gb          41.4 Gb

一些编辑将产生完全左对齐的结果。

#include <stdio.h>

int main ( void) {

    printf ( "Name          Available         Required\n");
    printf ( "------------- ----------------- ---------------\n");

    for ( int out = 0; out < 20; out += 3) {
        printf ( "%-14s", "Something");
        int span = printf ( "%.1f Gb", out * 10.1);
        printf ( "%*c%.1f Gb\n", 18 - span, ' ', out * 2.3);
    }

    return 0;
}

完全左对齐的结果:

Name          Available         Required
------------- ----------------- ---------------
Something     0.0 Gb            0.0 Gb
Something     30.3 Gb           6.9 Gb
Something     60.6 Gb           13.8 Gb
Something     90.9 Gb           20.7 Gb
Something     121.2 Gb          27.6 Gb
Something     151.5 Gb          34.5 Gb
Something     181.8 Gb          41.4 Gb

【讨论】:

    【解决方案3】:

    有时即使在printf() 行中创建一个可重用的宏/函数来处理各种值也很有趣。

    #include <assert.h>
    #include <limits.h>
    #include <stdio.h>
    #include <math.h>
    
    // https://stackoverflow.com/a/4589384/2410359
    #define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12))
    
    // Decimal digits possible in an integer `m`    
    #define IMAX_DIGITS(m) (IMAX_BITS(m)*28/93 + 1) //ceiling( bits * log10(2))
    
    #define ULLONG_STRING_SIZE (IMAX_DIGITS(ULLONG_MAX) + 1)
    #define KSCALE 1000u /* or 1024u */
    
    char* PrintMetric(char *dest, size_t n, unsigned long long b, char *suffix) {
      char prefix[] = "\0kMGTPEZY";
      int i = 0;
      while (i < sizeof prefix - 1 && b / pow(KSCALE, i) >= 99.95) {
        i++;
      }
      assert(i < sizeof prefix - 1);
      snprintf(dest, n, "%-.1f %.1s%s", b / pow(KSCALE, i), prefix + i, suffix);
      return dest;
    }
    
    #define PRT_BYTES(ull) \
        (PrintMetric((char [ULLONG_STRING_SIZE]){0}, ULLONG_STRING_SIZE, (ull), "b"))
    //               ^----------------------------^ Compound literal
    

    用法
    注意printf() 中的多种用法。

    #define GSCALE (1ull * KSCALE * KSCALE * KSCALE)
    void fooo() {
      puts("Name          Available         Required");
      puts("------------- ----------------- ---------------");
      // Notice 2 calls to PRT_BYTES()
      printf("%-*s %-*s %-s\n", 13, "Something", 17, PRT_BYTES(10.1*GSCALE), PRT_BYTES(2.3*GSCALE));
      printf("%-*s %-*s %-s\n", 13, "Something", 17, PRT_BYTES(99949), PRT_BYTES(99950));
      printf("%-*s %-*s %-s\n", 13, "Something", 17, PRT_BYTES(0), PRT_BYTES(ULLONG_MAX));
    }
    
    int main() {
      fooo();
      return 0;
    }
    

    输出

    Name          Available         Required
    ------------- ----------------- ---------------
    Something     10.1 Gb           2.3 Gb
    Something     99.9 kb           0.1 Mb
    Something     0.0 b             18.4 Eb
    

    【讨论】:

      【解决方案4】:

      另一种方法是使用不在同一格式字符串中的"Gb(yte)" 指示符并在标题中实现它们:

      #include <stdio.h>
      
      int main (void)
      {
          printf("Name            Available (Gbyte)   Required (Gbyte)\n");
          printf("---------       ----------          ---------\n");
          printf("Something       %-12.1f        %.1f ", 125.0, 1444.6);
      }
      

      输出:

      Name            Available (Gbyte)   Required (Gbyte)
      ---------       ----------          ---------
      Something       125.0               1444.6 
      

      【讨论】:

        猜你喜欢
        • 2022-06-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-07
        • 1970-01-01
        • 2018-01-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多