负数转换为无符号数据类型的理解及应用

本文探讨了负数转换为无符号整型数据时的变化及其原因,指出C语言中这种转换会导致数值变化但位模式不变。通过实例展示了在伺服电机控制中如何处理负数与无符号类型的转换,特别是在使用libmodbus库时的注意事项。
摘要由CSDN通过智能技术生成

负数转换为无符号数据类型的理解及应用

网上有大量的资料说明,负数转换为无符号整型数后,数值会发生变化,因此不建议将负数转换为无符号整型,但是真的是这样吗,为什么会这样呢,我参考了一些博客的内容,并通过一些实践来验证观点。

有符号整型和无符号整型的转换

一篇博客中这样写到:当执行一个运算时,若它的一个运算数是有符号的,而另一个数是无符号的,那么C语言会隐式地将有符号参数强制转换类型为无符号数,并假设这两个数是非负的,来执行这个运算。
那么,C语言强制转换的处理具体是怎么做的呢?
首先,整数在计算机中是以补码的形式存在的 ;
其次,在C语言中,处理同样字长的有符号数和无符号数之间的相互转换的一般规则是:数值可能会改变,但是位模式不变 ;
以-1为例进行说明,-1的补码是1111,1111,1111,1111;将-1转换成unsigned int 之后,它在内存中的表示还是没有改变,还是1111,1111,1111,1111
数据类型对于计算机底层是没有意义的,只有非0即1,只有在高层的应用程序中才有意义。因此,同样的储存对于应用程序而言可能会对应着不同的数据,例如1111,1111,1111,1111对于有符号的数而言,就表示**-1**,单对于无符号数而言,它表示UMax(作为正数,原码和反码补码都一样),这样理解可能还不是很明白,直接看输出的话可能会有一定帮助。

unsign int a=-4000;
printf("%d\n",a);
printf("%u\n",a);
printf("%x\n",a);

printf的输出格式:
%d表示以十进制形式输出带符号整数;
%u表示以十进制形式输出无符号整数;
%x表示以十六进制形式输出无符号整数;
运算的结果可以先猜一下:
在这里插入图片描述
以十进制的形式输出结果理解上并没有什么难度,问题是以十六进制形式输出的无符号整数和以带符号整数直接转换为十六进制输出的话,结果是一致的。说明了上述的观点是正确的。
在这里插入图片描述

有符号类型和无符号类型的转换应用实例

为什么要专门聊一下有关有符号整型和无符号整型的转换呢,是因为控制伺服电机时,其位置控制模式中有控制增量位置和控制绝对位置两种。控制增量位置的话就可能会有负数出现,控制绝对位置的话,就只有正数,而libmodbus库中关于modbus_write_registers的定义如下:

int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src);

其中关于src的数据类型定为uint16_t,在libmodbus库中的定义uint16_t是unsigned short类型,因此需要注意负数和无符号类型的转换。
从上一节内容可知,对负数进行强制转换为无符号类型,十六进制的输出结果与有符号的输出结果相同,因此此处可强制转换。

//伺服电机反转的代码
void myWidget::on_pushButton_clicked()
{
	int rc;
	nb=ADDRESS_END-ADDRESS_STRAT;
	tab_reg=(uint16_t*)malloc(nb*sizeof(uint16_t));
	memset(tab_reg,0,nb*sizeof(uint16_t));

	/*写入保持寄存器数值*/
	nb_loop=nb_fail=0;
	while(nb_loop++<LOOP)
	{
		for(addr=ADDRESS_START;addr<ADDRESS_START+1;addr++)
		{
			const uint32_t num1=-10000;
			qDebug()<<num1;
			int i;
			for(i=0;i<1;i++)
			{
				tab_reg[0]=(uint16_t)(0x0000FFFF&num1);
				tab_reg[1]=(uint16_t)(0xFFFF0000&num1)>>16;
				qDebug()<<tab_reg[i];
			}
			{
				rc=modbus_write_registers(ctx,addr,2,tab_reg);
				if(rc!=2)
				{
					fprintf(stderr,"%s\n",modbus_strerror(errno));
					qDebug()<<"rc错误"<<modbus_strerror(errno);
					nb_fail++;
				}
				else
				{
					qDebug()<<"链接成功";
					printf("reg[%d]=%d(0x%x)\n",addr,tab_reg[addr],tab_reg[addr]);
					qDebug()<<"rc收到:"<<tab_reg[addr];
				}
			}
		}
	}
}

在这里插入图片描述

参考文献

1.负数时的有符号整型和无符号整型的转换
2: C/C++中printf和C++中cout的输出格式
3.libmodbus官方手册中文翻译

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值