AtmelStudio 中大值的 C strtoul() 错误
C strtoul() bug for large values in AtmelStudio
我需要将大字符数转换为长字符数,以便在 AtmelStudio 上对我的 Atmega8 芯片进行编程。
我试过使用 atol()
和 strtoul()
但它不起作用。我在 google 上读到 strtoul()
有一个错误,它只允许使用较小的值。我试过了,这是真的。我可以使用 strtoul()
将字符“250”转换为长整数,但不能将“5555”转换为长整数。
我了解到解决方法是创建您自己的 strtoul() 函数,但我该怎么做呢?我不知道strtoul()
的实现,它是库中的extern。
这不起作用:
char *my_time = "2505";
unsigned long new2 = (unsigned)strtoul(my_time, NULL, 10);
请运行这个测试程序并告诉我们它打印了什么。如果您没有 printf
,想出 某种方式 来让我们获得与该程序打印的相同信息。 (如果你没有 errno
,那部分不如其他部分重要。)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(void)
{
const char *my_time = "2505";
char *endptr;
unsigned long value;
errno = 0;
value = strtoul(my_time, &endptr, 10);
printf("value=%lu endptr=%s delta=%ld errno=%d (%s)\n",
value, endptr, (long)(endptr - my_time),
errno, strerror(errno));
return 0;
}
将(无符号)十进制字符串转换为整数的核心是:
unsigned long str2int(const char *s)
{
unsigned long x = 0;
while(isdigit(*s))
{
x *= 10;
x += *s++ - '0';
}
return x;
}
它真的不是很复杂,它只是遍历数字,边走边建立值。 *s++ - '0'
可能是我无法控制自己的 "experienced C programmer's maximum terseness syndrome" 的标志。我也有点着急。更明确的方法可能是:
while(isdigit(*s))
{
x *= 10; /* Each new digit makes the old ones worth more. */
const int digit = *s - '0'; /* Convert digit character to small int. */
x += digit; /* Add the current digit. */
++s;
}
因此,例如,考虑 "432"
的输入。它会被计算为 ((0 * 10 + 4) * 10 + 3) * 10 + 2.
由于您在 8 位微控制器上工作,如果您的应用程序将自己限制在 uint16_t
而不是 unsigned long
,您可能会获得大量代码 space仅限于 65,536 以下的整数。
将表示机器 unsigned long
类型范围内数字的十进制数字字符串转换为 unsigned long
值非常容易。例如:
unsigned long my_atoul(const char *digits) {
unsigned long result = 0;
const char *c = digits;
while ('0' <= *c && *c <= '9') {
result = result * 10 + (*(c++) - '0');
}
return result;
}
如果您想要额外的功能(例如基数的选择)或非数字或超长输入的不同行为,那么可以在该基本方法之上实现这些东西。
我需要将大字符数转换为长字符数,以便在 AtmelStudio 上对我的 Atmega8 芯片进行编程。
我试过使用 atol()
和 strtoul()
但它不起作用。我在 google 上读到 strtoul()
有一个错误,它只允许使用较小的值。我试过了,这是真的。我可以使用 strtoul()
将字符“250”转换为长整数,但不能将“5555”转换为长整数。
我了解到解决方法是创建您自己的 strtoul() 函数,但我该怎么做呢?我不知道strtoul()
的实现,它是库中的extern。
这不起作用:
char *my_time = "2505";
unsigned long new2 = (unsigned)strtoul(my_time, NULL, 10);
请运行这个测试程序并告诉我们它打印了什么。如果您没有 printf
,想出 某种方式 来让我们获得与该程序打印的相同信息。 (如果你没有 errno
,那部分不如其他部分重要。)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(void)
{
const char *my_time = "2505";
char *endptr;
unsigned long value;
errno = 0;
value = strtoul(my_time, &endptr, 10);
printf("value=%lu endptr=%s delta=%ld errno=%d (%s)\n",
value, endptr, (long)(endptr - my_time),
errno, strerror(errno));
return 0;
}
将(无符号)十进制字符串转换为整数的核心是:
unsigned long str2int(const char *s)
{
unsigned long x = 0;
while(isdigit(*s))
{
x *= 10;
x += *s++ - '0';
}
return x;
}
它真的不是很复杂,它只是遍历数字,边走边建立值。 *s++ - '0'
可能是我无法控制自己的 "experienced C programmer's maximum terseness syndrome" 的标志。我也有点着急。更明确的方法可能是:
while(isdigit(*s))
{
x *= 10; /* Each new digit makes the old ones worth more. */
const int digit = *s - '0'; /* Convert digit character to small int. */
x += digit; /* Add the current digit. */
++s;
}
因此,例如,考虑 "432"
的输入。它会被计算为 ((0 * 10 + 4) * 10 + 3) * 10 + 2.
由于您在 8 位微控制器上工作,如果您的应用程序将自己限制在 uint16_t
而不是 unsigned long
,您可能会获得大量代码 space仅限于 65,536 以下的整数。
将表示机器 unsigned long
类型范围内数字的十进制数字字符串转换为 unsigned long
值非常容易。例如:
unsigned long my_atoul(const char *digits) {
unsigned long result = 0;
const char *c = digits;
while ('0' <= *c && *c <= '9') {
result = result * 10 + (*(c++) - '0');
}
return result;
}
如果您想要额外的功能(例如基数的选择)或非数字或超长输入的不同行为,那么可以在该基本方法之上实现这些东西。