C 中的多个动态浮点格式说明符
Multiple dynamic float format specifier in C
我遇到过几次使用 float
变量的情况,这些变量必须 printf
正确格式化并具有一定数量的小数位。我知道在 C 中,您可以通过使用以下符号来指定小数位数和总位数,从而轻松地格式化 float
变量:
// Where x and y are natural numbers
printf("%<x>.<y>f", myFloat);
而且我还知道您可以使用两个变量将 *
符号用于 dynamically format a float
,如下所示:
// Where x and y are natural numbers
printf("%*.*f", x, y, myFloat);
但是我最近陷入了一个非常多余的情况:当我不得不printf
输出多个float
数字时相同的动态格式 我必须重复这两个 x
和 y
变量数千次。 我总是喜欢 #define
我的常数,这样我就可以很容易地改变它们未来,所以我的程序看起来像:
#define FLOAT_FORMAT_SIZE 10
#define FLOAT_FORMAT_PRECISION 3
int main(int argc, char *argv[]) {
// Anything I have to do...
// Output
printf("%*.*f, %*.*f, %*.*f, %*.*f",
FLOAT_FORMAT_SIZE, FLOAT_FORMAT_PRECISION, myFloat1,
FLOAT_FORMAT_SIZE, FLOAT_FORMAT_PRECISION, myFloat2,
FLOAT_FORMAT_SIZE, FLOAT_FORMAT_PRECISION, myFloat3,
FLOAT_FORMAT_SIZE, FLOAT_FORMAT_PRECISION, myFloat4
);
return 0;
}
现在你可以看到这有点太多余了,我想知道:有没有什么特殊的系统常量或格式技术我可以用于避免为每个 float
I printf
out?
一遍又一遍地重复相同的值
我不想创建自己的函数来打印这些数字,我显然可以做到,但如果可能的话,我想在较低的层次上解决它。
您可以在 运行 时间创建格式字符串,并根据需要多次使用它。
// Create the format string.
char formatString[100]; // Make it large enough.
sprintf(formatString, "%%%d.%df", FLOAT_FORMAT_SIZE, FLOAT_FORMAT_PRECISION);
// Use the format string to print a float
printf(formatString, myFloat1);
printf(formatString, myFloat2);
printf(formatString, myFloat3);
printf(formatString, myFloat4);
您可以编写一个宏来定义打印浮点数的默认方式:
#define FLOAT_FORMAT_SIZE 10
#define FLOAT_FORMAT_PRECISION 3
#define M_STR(x) M_STR_(x)
#define M_STR_(x) #x
#define FLOAT_FMT \
"%" M_STR(FLOAT_FORMAT_SIZE) \
"." M_STR(FLOAT_FORMAT_PRECISION) \
"f"
那么您的 printf
语句将如下所示:
printf(FLOAT_FMT ", " FLOAT_FMT ", " FLOAT_FMT ", " FLOAT_FMT,
myFloat1, myFloat2, myFloat3, myFloat4);
宏及其使用方式均使用字符串文字连接。格式字符串是在编译时创建的,因此会触发有关格式和参数类型不匹配的警告。
当然,格式字符串是否非常可读是有争议的。
编辑:这是如何工作的?宏 M_STR
"stringifies" 它的参数;它把它变成一个 C 字符串文字。宏定义中可用的运算符 #
实现了这一点。
必须使用到辅助宏的间接寻址M_STR_
,这样宏参数将首先展开。如果没有这个辅助宏,M_STR(FLOAT_FORMAT_SIZE)
将扩展为 "FLOAT_FORMAT_SIZE"
。通过 M_STR_
绕道,宏 FLOAT_FORMAT_SIZE
在变成字符串之前被扩展,结果字符串是 "10"
.
因此,宏 FLOAT_FMT
扩展为
"%" "10" "." "3" "f"
C 编译器连接相邻的字符串文字,因此宏的最终结果等同于 "%10.3f"
。
构造格式字符串时也是如此:
printf(FLOAT_FMT ", " FLOAT_FMT ", " FLOAT_FMT ", " FLOAT_FMT,
myFloat1, myFloat2, myFloat3, myFloat4);
有效:
printf("%10.3f, %10.3f, %10.3f, %10.3f",
myFloat1, myFloat2, myFloat3, myFloat4);
此解决方案的缺点是字符串和宏的并置有点难以阅读。
我遇到过几次使用 float
变量的情况,这些变量必须 printf
正确格式化并具有一定数量的小数位。我知道在 C 中,您可以通过使用以下符号来指定小数位数和总位数,从而轻松地格式化 float
变量:
// Where x and y are natural numbers
printf("%<x>.<y>f", myFloat);
而且我还知道您可以使用两个变量将 *
符号用于 dynamically format a float
,如下所示:
// Where x and y are natural numbers
printf("%*.*f", x, y, myFloat);
但是我最近陷入了一个非常多余的情况:当我不得不printf
输出多个float
数字时相同的动态格式 我必须重复这两个 x
和 y
变量数千次。 我总是喜欢 #define
我的常数,这样我就可以很容易地改变它们未来,所以我的程序看起来像:
#define FLOAT_FORMAT_SIZE 10
#define FLOAT_FORMAT_PRECISION 3
int main(int argc, char *argv[]) {
// Anything I have to do...
// Output
printf("%*.*f, %*.*f, %*.*f, %*.*f",
FLOAT_FORMAT_SIZE, FLOAT_FORMAT_PRECISION, myFloat1,
FLOAT_FORMAT_SIZE, FLOAT_FORMAT_PRECISION, myFloat2,
FLOAT_FORMAT_SIZE, FLOAT_FORMAT_PRECISION, myFloat3,
FLOAT_FORMAT_SIZE, FLOAT_FORMAT_PRECISION, myFloat4
);
return 0;
}
现在你可以看到这有点太多余了,我想知道:有没有什么特殊的系统常量或格式技术我可以用于避免为每个 float
I printf
out?
我不想创建自己的函数来打印这些数字,我显然可以做到,但如果可能的话,我想在较低的层次上解决它。
您可以在 运行 时间创建格式字符串,并根据需要多次使用它。
// Create the format string.
char formatString[100]; // Make it large enough.
sprintf(formatString, "%%%d.%df", FLOAT_FORMAT_SIZE, FLOAT_FORMAT_PRECISION);
// Use the format string to print a float
printf(formatString, myFloat1);
printf(formatString, myFloat2);
printf(formatString, myFloat3);
printf(formatString, myFloat4);
您可以编写一个宏来定义打印浮点数的默认方式:
#define FLOAT_FORMAT_SIZE 10
#define FLOAT_FORMAT_PRECISION 3
#define M_STR(x) M_STR_(x)
#define M_STR_(x) #x
#define FLOAT_FMT \
"%" M_STR(FLOAT_FORMAT_SIZE) \
"." M_STR(FLOAT_FORMAT_PRECISION) \
"f"
那么您的 printf
语句将如下所示:
printf(FLOAT_FMT ", " FLOAT_FMT ", " FLOAT_FMT ", " FLOAT_FMT,
myFloat1, myFloat2, myFloat3, myFloat4);
宏及其使用方式均使用字符串文字连接。格式字符串是在编译时创建的,因此会触发有关格式和参数类型不匹配的警告。
当然,格式字符串是否非常可读是有争议的。
编辑:这是如何工作的?宏 M_STR
"stringifies" 它的参数;它把它变成一个 C 字符串文字。宏定义中可用的运算符 #
实现了这一点。
必须使用到辅助宏的间接寻址M_STR_
,这样宏参数将首先展开。如果没有这个辅助宏,M_STR(FLOAT_FORMAT_SIZE)
将扩展为 "FLOAT_FORMAT_SIZE"
。通过 M_STR_
绕道,宏 FLOAT_FORMAT_SIZE
在变成字符串之前被扩展,结果字符串是 "10"
.
因此,宏 FLOAT_FMT
扩展为
"%" "10" "." "3" "f"
C 编译器连接相邻的字符串文字,因此宏的最终结果等同于 "%10.3f"
。
构造格式字符串时也是如此:
printf(FLOAT_FMT ", " FLOAT_FMT ", " FLOAT_FMT ", " FLOAT_FMT,
myFloat1, myFloat2, myFloat3, myFloat4);
有效:
printf("%10.3f, %10.3f, %10.3f, %10.3f",
myFloat1, myFloat2, myFloat3, myFloat4);
此解决方案的缺点是字符串和宏的并置有点难以阅读。