我刚刚在十六进制整数(例如0xFFFF)与十进制整数(例如2)相乘时,在我的代码中发现了一个错误.这是出现问题的代码:
print_int_new_line(0xFFFF*2);
print_int_new_line(65535*2);
Run Code Online (Sandbox Code Playgroud)
执行此代码会给我以下结果:
65534
131070
Run Code Online (Sandbox Code Playgroud)
这是相关的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 != '\0'; 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;
}
Run Code Online (Sandbox Code Playgroud)
有关我的设置的一些信息:
MCU:ATmega2560电路板:Arduino Mega2560 UART波特率:38400 IDE:Atmel Studio 7.0.4.1417
使用AVR工具链.
我在这个 stackoverflow页面上读到,在hex和dec int之间可以进行乘法.此外,在在线 c编译器中进行测试可以得到正确的输出.
任何人都可以给我一个解释吗?
此行为是由于处理十进制和十六进制整数常量的差异.
对于这两个0xFFFF和65535,编译器将首先尝试将值转换为int.但是,由于该平台具有一个16位的int类型,其中INT_MAX是32767,不能进行这种转换.
关键的区别在于下一步.对于十六进制常量0xFFFF,编译器将尝试将其转换为a 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);
Run Code Online (Sandbox Code Playgroud)
当2被提升为乘法时:
print_int_new_line((unsigned int)65535*(unsigned int)2);
print_int_new_line((long int)65535*(long int)2);
Run Code Online (Sandbox Code Playgroud)
第unsigned int一次乘法的结果太小而无法保存完整结果,因此将其截断为65534.在long int可容纳的结果,所以它产生的正确答案131070.
您可以long int通过附加L(ie 0xFFFFL)强制十六进制常量来使用a .