【问题标题】:Specifying maximum printf field width for numbers (truncating if necessary)?为数字指定最大 printf 字段宽度(必要时截断)?
【发布时间】:2012-04-14 17:42:25
【问题描述】:

您可以使用 printf 字段宽度说明符截断字符串:

printf("%.5s", "abcdefgh");

> abcde

不幸的是它不适用于数字(将d替换为x是一样的):

printf("%2d",   1234);  // for 34
printf("%.2d",  1234);  // for 34
printf("%-2d",  1234);  // for 12
printf("%-.2d", 1234);  // for 12

> 1234

是否有一种简单/简单的方法来指定要打印的位数,即使这意味着截断数字?

MSDN 特别是says that it will not happen,这似乎是不必要的限制。 (是的,它可以通过创建字符串等来完成,但我希望有一个 “printf trick” 或聪明的组合。)

【问题讨论】:

  • 我还不能发表评论,所以我要添加一个新答案,在数学上不可能比 log 更快地进行截断,如果你找到了,那么你可以从它。

标签: printf truncate format-specifiers


【解决方案1】:

来自 Bash 命令行的示例:

localhost ~$ printf "%.3s\n" $(printf "%03d"  1234)
123
localhost ~$ 

【讨论】:

    【解决方案2】:

    为什么不从左边?唯一的区别是使用简单的除法:

    printf("%2d", 1234/100); // you get 12
    

    【讨论】:

    • 当我说我的解决方案不能从左边截断时,我并不是说不可能;正如您所演示的,您可以使用除法。我没有使用它的原因是因为与模数不同,它可以轻松地为您提供 any 数字的最右侧 n 位,要从左侧截断,您必须首先确定数字中的位数,然后才能进行除法(在您的示例中,如果数字为12345,则必须使用1000 而不是100)。这会产生更多的工作来首先确定位数,然后乘以 10 得到一个掩码,然后除以,所有这些都只是为了截断。 :-/
    • 可能有(可能是)我没有想到的极端情况,但像num / pow(10, (int)log10(num) - digits + 1); 这样的东西应该适用于简单的情况(假设基数为 10)。
    【解决方案3】:

    您可以使用 snprintf 从右侧截断

    char buf[10];
    static const int WIDTH_INCL_NULL = 3;
    
    snprintf(buf, WIDTH_INCL_NULL, "%d", 1234); // buf will contain 12
    

    【讨论】:

    • 使用缓冲区和硬编码值,因此更不理想——使用动态分配的内存会更糟。
    【解决方案4】:

    如果要从右侧截断,可以将数字转换为字符串,然后使用字符串字段宽度说明符。

    "%.3s".format(1234567.toString)
    

    【讨论】:

    • 我已经承认您将它们转换为字符串;这个问题是关于原始数字的。据推测(有人必须检查才能确定,但​​这似乎是合理的),printf 中的转换比手动转换更优化。
    【解决方案5】:

    就像我的许多最佳想法一样,答案是在我躺在床上等待入睡时得到的(当时除了思考之外别无他法)。

    使用模数!

    printf("%2d\n", 1234%10);   // for 4
    printf("%2d\n", 1234%100);  // for 34
    
    printf("%2x\n", 1234%16);   // for 2
    printf("%2x\n", 1234%256);  // for d2
    

    这并不理想,因为它不能从左侧截断(例如,12 而不是 34),但它适用于主要用例。例如:

    // print a decimal ruler
    for (int i=0; i<36; i++)
      printf("%d", i%10);
    

    【讨论】:

    • 如果要从左边截断,假设值为整数,除法即可。例如:1234/100 // for 12
    • @ortang,是的,我知道,但它是not the same as truncating from the right
    • 请注意,使用模数对负数是不安全的。 -9999 % 1000 给出 1 或 -999,具体取决于您的编译器、CPU 和使用的编译器标志。大多数现代组合倾向于给出 -999,因为它们将 -9999 / 1000 舍入为零(结果给出 -9,而不是 -10)。所以仍然存在缓冲区和字段溢出的风险!
    猜你喜欢
    • 1970-01-01
    • 2018-11-14
    • 1970-01-01
    • 2011-02-17
    • 1970-01-01
    • 2013-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多