科学记数法对于C中的整数常量是否安全?

有一段时间,我一直用科学记数法表示常量中10的大功率,所以我不必计算零。 例如

#define DELAY_USEC 1e6 

一位同事指出这不安全,因为它不是一个整数,并且不能保证总是完全等于1000000。 文档似乎证实了这一点,但我想知道它在实用性方面是否真实。 有没有办法用速记安全地声明十进制的整数? 将它强制转换为定义中的int是否安全?

从理论上讲,没有。 两种语言都没有指定如何表示浮点值,或者哪些值可以精确表示。 (更新:显然,C11确实推荐了一种表示法.C ++和旧的C方言,不这样做)。

在实践中,是的,对于相当大的价值范围。 您可能遇到的任何实现都将使用64位IEEE表示forms进行double 。 这可以精确地表示高达2 53 (大约9×10 15 )的任何整数值。 它当然可以表示32位整数类型可表示的任何内容。

您想要使用用户定义的文字:

 constexpr long long operator "" _k(long long l) { return l * 1000; } constexpr long long operator "" _m(long long l) { return l * 1000 * 1000; } 

然后你可以简单地做:

 long long delay = 1_m; long long wait = 45_k; 

你具体问十个权力。 1e6将是一百万。 你可以在没有发生任何不良事件的情况下升至1e22 。 但是,请注意,在C ++和C中, 1e6double常量,而不是整数常量。

十的负面力量是另一回事。 1e-1和所有低权力都是不精确的。

似乎gcc假定使用科学记数法定义的常量作为浮点数,除非它是强制转换的。

一个简单的C代码显示了这个:

 #include  #define DELAY_USEC_FP 1e6 #define DELAY_USEC_INT (unsigned int) 1e6 int main() { printf("DELAY_USEC_FP: %f\n", DELAY_USEC_FP); printf("DELAY_USEC_INT: %u\n", DELAY_USEC_INT); return 0; } 

在x86-64机器上, gcc生成此汇编代码( $ gcc -S define.c ):

 [...] ; 0x4696837146684686336 = 1e6 in double-precision FP IEEE-754 format movabsq $4696837146684686336, %rax [...] call printf movl $1000000, %esi [...] call printf movl $0, %eax 

如此处所述,10e15和10e22分别是10个数字的最大功率,它们分别具有简单和双精度浮点格式的精确表示。

使用32位或64位整数类型无法表示十个数字的更大功率。

你永远不会在小于INT_MAX东西上得到舍入错误,因为double的规范设置了52位供你使用 。 你的“小数分量”只是你的整数,你的“指数”将是1,浮点数并不挣扎。

它真的不安全,因为编译器会将它视为浮点数,因此精度限制为53位而不是64位整数(long int),您可以阅读有关浮点数numbrers的更多信息。

http://en.wikipedia.org/wiki/Floating_point