尝试获取 unsigned long long 的最大值时的奇怪行为

Strange behavior when attempting to obtain number of digits of unsigned long long´s maximum

我喜欢奢华。我想发明一种方法让你获得 unsigned long long int 最大拥有的位数。这一切都是自动的。 这是:

#include <limits.h>
#include <string.h>

#define STRINGIFY(x) #x
#define ULLONG_MAX_STRING STRINGIFY(ULLONG_MAX)
#define NUMERAL_MAXIMUM strlen(ULLONG_MAX_STRING)

这是否像描述的那样工作?


现在谈谈几乎可以回答上面问题的奇怪行为。 如果我像这样声明一个变量(-std=c99 具体):

char variable [NUMERAL_MAXIMUM];

它没有声明自动作用域变量,大小为 20 的数组,而是在程序到达该行之前终止程序。尽管如果我不这样声明变量,什么都不会终止,程序会继续工作。


这是怎么回事?


更新:更奇怪的是,只有当我使用这个获得的长度作为数组的大小时,程序才会这样做。

当您使用定义时,您必须知道它在编译开始之前已经过预处理。

这意味着调试起来会变得非常困难,因为代码只是粘贴到那里,编译器没有检查语义、类型错误等。

尝试打印 ULLONG_MAX 及其字符串。在您使用 STRINGIFY 时检查 none 是否有奇怪的值。

IIUC,OQ 想要打印十进制最大值所需的大小。以下适用于 8 位到 64 位的大小,至少对于 CHAR_BIT==8 :

#include <stdio.h>
#include <limits.h>

#define ASCII_SIZE(s) ((3+(s) * CHAR_BIT) *4 / 13)

int main(void)
{
printf("unsigned char : %zu\n", ASCII_SIZE(sizeof(unsigned char)) );
printf("unsigned short int : %zu\n", ASCII_SIZE(sizeof(unsigned short int)) );
printf("unsigned int : %zu\n", ASCII_SIZE(sizeof(unsigned int)) );
printf("unsigned long : %zu\n", ASCII_SIZE(sizeof(unsigned long)) );
printf("unsigned long long : %zu\n", ASCII_SIZE(sizeof(unsigned long long)) );

printf("          Ding : %u\n", UINT_MAX );
printf("     Lang Ding : %lu\n", ULONG_MAX );
printf("Heel lang Ding : %llu\n", ULLONG_MAX );

return 0;
}

输出:

unsigned char : 3
unsigned short int : 5
unsigned int : 10
unsigned long : 20
unsigned long long : 20
          Ding : 4294967295
     Lang Ding : 18446744073709551615
Heel lang Ding : 18446744073709551615

我不知道是什么原因导致您的崩溃。为了调查我首先要查看预处理器输出 (cc -E)

但更重要的是,你的整个方法都是错误的。 ULLONG_MAX 的预处理器扩展的长度不能保证与格式化为十进制数字字符串的数字的长度有任何关系。我检查的第一个系统是这样的:

#define ULLONG_MAX (LLONG_MAX * 2ULL + 1)

完全展开后变成这样:

(9223372036854775807LL * 2ULL + 1)

如果你设法得到 strlen,它会比 18446744073709551615 的长度大很多,后者是相同的数字,以你可能想的方式表示的。

这意味着您的缓冲区可能太大了。但它也可能太小了。想想#define ULLONG_MAX 0xffffffffffffffff.

的可能性

您需要使用数字运算而不是字符串运算来计算缓冲区大小。一个正整数n的十进制表示的位数是ceil(log10(n))+1。您不能在预处理器中准确地进行该计算,因为它不进行浮点运算。但是你可以做一个合理的近似。

ULLONG_MAX 的 base 2 表示中的位数是类型中的位数:sizeof(unsigned long long)*CHAR_BIT。小数位数大致为基数2位数乘以log(2)/log(10)。现在 wildplasser 刚刚发布了一个答案,所以我会在这里停下来指出 log(2)/log(10) 略低于 4/13,这就是 wildplasser 的答案有效的原因。

您必须再次展开 STRINGIFY 的参数以获得常量

的值
#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)

那么这里你应该使用sizeof运算符

#define ULLONG_MAX_STRING STRINGIFY(ULLONG_MAX)
#define NUMERAL_MAXIMUM (sizeof(ULLONG_MAX_STRING)-1)

它在编译时执行所有操作。