AVR C 十六进制和十进制乘法不符合预期
AVR C hex and dec multiplication not as expected
我刚刚在将十六进制整数(例如 0xFFFF)与十进制整数(例如 2)相乘时在我的代码中发现了一个错误。这是出现问题的代码:
print_int_new_line(0xFFFF*2);
print_int_new_line(65535*2);
执行这段代码得到以下结果:
65534
131070
这是相关的 UART 代码:
void print_int_new_line(uint64_t data) {
print_int(data);
print_new_line();
}
void print_int(uint64_t data) {
char data_buffer[(int)(log(data)+2)]; // size of the number (log(number)+1) + 1 for the /0
ultoa(data, data_buffer, 10); // convert the int to string, base 10
// print the newly created string
print_string(data_buffer);
}
void print_string(char * data) {
// transmit the data char by char
for(; *data != '[=12=]'; data++){
USART_transmit(data);
}
}
void USART_transmit(const char * data){
/* Wait for empty transmit buffer */
while ( !( UCSR0A & (1<<UDRE0)) )
;
/* Put data into buffer, sends the data */
UDR0 = *data;
}
关于我的设置的一些信息:
单片机:ATmega2560
开发板:Arduino Mega2560
串口波特率:38400
IDE:Atmel Studio 7.0.4.1417
使用 AVR 工具链。
我阅读了 Whosebug page that multiplication is possible between hex and dec ints. Also, testing this in an online c 编译器给出了正确的输出。
谁能给我解释一下?
此行为是由于处理十进制和十六进制整数常量的差异所致。
对于 0xFFFF
和 65535
,编译器将首先尝试将值转换为 int
。但由于平台有一个 16 位 int
类型,其中 INT_MAX
是 32767
,无法执行该转换。
关键区别在于下一步。对于十六进制常量 0xFFFF
,编译器会尝试将其转换为 unsigned int
,这相当于 (unsigned int)65535
。但是,对于十进制常量,不会尝试转换为无符号类型。下一次转换尝试是 long int
。这将成功并等效于 (long int)65535
.
所以对 print_int_new_line
的调用等同于:
print_int_new_line((unsigned int)65535*2);
print_int_new_line((long int)65535*2);
而当 2
被提升为乘法时:
print_int_new_line((unsigned int)65535*(unsigned int)2);
print_int_new_line((long int)65535*(long int)2);
第一次乘法的unsigned int
结果太小,无法容纳完整的结果,因此被截断为65534
。 long int
可以保存结果,因此它会产生 131070
.
的正确答案
您可以通过附加 L
(即 0xFFFFL
)来强制十六进制常量使用 long int
。
我刚刚在将十六进制整数(例如 0xFFFF)与十进制整数(例如 2)相乘时在我的代码中发现了一个错误。这是出现问题的代码:
print_int_new_line(0xFFFF*2);
print_int_new_line(65535*2);
执行这段代码得到以下结果:
65534
131070
这是相关的 UART 代码:
void print_int_new_line(uint64_t data) {
print_int(data);
print_new_line();
}
void print_int(uint64_t data) {
char data_buffer[(int)(log(data)+2)]; // size of the number (log(number)+1) + 1 for the /0
ultoa(data, data_buffer, 10); // convert the int to string, base 10
// print the newly created string
print_string(data_buffer);
}
void print_string(char * data) {
// transmit the data char by char
for(; *data != '[=12=]'; data++){
USART_transmit(data);
}
}
void USART_transmit(const char * data){
/* Wait for empty transmit buffer */
while ( !( UCSR0A & (1<<UDRE0)) )
;
/* Put data into buffer, sends the data */
UDR0 = *data;
}
关于我的设置的一些信息:
单片机:ATmega2560 开发板:Arduino Mega2560 串口波特率:38400 IDE:Atmel Studio 7.0.4.1417
使用 AVR 工具链。
我阅读了
谁能给我解释一下?
此行为是由于处理十进制和十六进制整数常量的差异所致。
对于 0xFFFF
和 65535
,编译器将首先尝试将值转换为 int
。但由于平台有一个 16 位 int
类型,其中 INT_MAX
是 32767
,无法执行该转换。
关键区别在于下一步。对于十六进制常量 0xFFFF
,编译器会尝试将其转换为 unsigned int
,这相当于 (unsigned int)65535
。但是,对于十进制常量,不会尝试转换为无符号类型。下一次转换尝试是 long int
。这将成功并等效于 (long int)65535
.
所以对 print_int_new_line
的调用等同于:
print_int_new_line((unsigned int)65535*2);
print_int_new_line((long int)65535*2);
而当 2
被提升为乘法时:
print_int_new_line((unsigned int)65535*(unsigned int)2);
print_int_new_line((long int)65535*(long int)2);
第一次乘法的unsigned int
结果太小,无法容纳完整的结果,因此被截断为65534
。 long int
可以保存结果,因此它会产生 131070
.
您可以通过附加 L
(即 0xFFFFL
)来强制十六进制常量使用 long int
。