uboot环境变量do_printenv-字符串解析学习

通过学习do_printenv这个函数,去学习内里的字符串解析方法。

第一步,研究do_printenv要知道uboot中的环境变量是怎样存储的。

在do_printenv里会调用到env_get_char函数,返回值是unsigned char类型的。
通过env_get_char函数可以获得一个字符。
从哪里获得呢?
从default_environment[ ]这个数组获得。
这个数组里面的元素排列都是紧密排列的,用\0隔开、
在这里插入图片描述
就是这样排列的。
相当于这样
char buf[ ] = {“abc” “\0” “ccd” “\0”};
然后我测试了一下,如果改成下面这样子
char buf[ ] = {“abc\0ccd\0”};
效果是一模一样的,但是如果试图用printf()去打印出来的话就不全,因为printf()遇到\0就停了。可以试着用puts打印出来,两种的效果是一样的
结论就是:
环境变量放在一个字符串数组里面,紧密排列,各个环境变量之间是用\0分开的。
而且还要注意,这里存的是环境变量=xxxxx这样的信息,而不只是环境变量名字。

知道存储方法后,要怎么取?
下面是do_printenv函数的截图
在这里插入图片描述
分两部分分析
第一部分: end if argc ==1 之前
如果只传1个参数,也就是只print或者printenv的话,执行第一部分argc==1的情况
这个很好分析。
有一些细节要注意,就是for循环里面++nxt,为什么不可以是nxt++,其实是可以的,因为这是在for循环的表达式3里面。

引用:
链接: for循环中++i 和 i++ 的区别
根据上面的for循环的语法定义 ++i 和 i++的结果是一样的,都要等代码块执行完毕才能执行语句3,但是性能是不同的。在大量数据的时候++i的性能要比i++的性能好原因:
i++由于是在使用当前值之后再+1,所以需要一个临时的变量来转存。
而++i则是在直接+1,省去了对内存的操作的环节,相对而言能够提高性能
.
为了保险起见,我把++nxt改成nxt++,然后烧录到到sd卡里面启动,效果一样的。
最后一句

printf("\nEnvironment size: %d/%ld bytes\n",i, (ulong)ENV_SIZE);

结果
在这里插入图片描述
前面的i是遍历完所有的环境变量,得到的大小,如果你用set xxx=yyy去增加环境变量的话,则这个值会变,不再是308了。
后面的16380是怎么来的呢?
在这里插入图片描述
在这里插入图片描述

通过这些宏得到是16380,注意ENV_HEADER_SIZE到底是哪个,要分清楚哪个宏有定义哪个宏没定义。

第二部分: 剩下的,如果传多个参数的
在这里插入图片描述
这里困扰我的主要在envmatch函数里面
如果改写一下就会好一点理解。

int envmatch (uchar *s1, int i2)
{

	while (*s1 == env_get_char(i2++))
	{
		if (*s1++ == '=')
		{
			return(i2);
		}
	}
	if (*s1 == '\0' && env_get_char(i2-1) == '=')
		return(i2);
	return(-1);
}

我测试过,改成这样重新烧录效果一样,证明改写的方法是正确的。
另外很重要的点再i2++和*s1++上,一定要注意
env_get_char(i2++)的理解:
i2++还好理解一点,没那么容易栽在这里,这里就是说先env_get_char(i2),然后再i2=i2+1;

if (*s1++ == '=') if语句的理解

尽管这个条件不成立,但是条件里面执行了的涉及到赋值运算的话,那么还是要进行赋值的,也就是每一次判断的时候,s1其实会变,这里的s改变就会导致while循环里面的s1也跟着改变。

另外虽然++的优先级是大于*,但是就不能理解为是先s1++了再解引用,这是不对的。
正确的理解是这样
链接: 应该理解为,由于后++优先级高于*,应该先p++,后取值,但因为是后++,所以先执行*p,然后等赋值完成以后,p再++。.

对于这里,也就是说先解引用s1,即*s1,判断完之后了,s1再++。
对于这里我也做了测试,我把整一套的k=envmatch()给再现了一次

#include <stdio.h>
//用到的函数的声明
static char env_get_char_init (int index);
char env_get_char (int index);
int envmatch (char *s1, int i2);

int main(int argc,char *argv[])
{
	int k;
	char *name = argv[1];
	k = envmatch((char *)name, 4); //传参4是跟根据我假设的default_environment[]而定的
	printf("k = %d\n",k);



	return 0;
}
int envmatch (char *s1, int i2)
{
	/* printf("before while: i2 = %d\n",i2);
	printf("before while: s1 = %c\n",*s1);
	printf("before while: env_get_char(i2++) = %c\n",env_get_char(i2++));
	i2=i2-1; */
	while (*s1 == env_get_char(i2++))
	{
		/* printf("after while : *s1 = %c\n",*s1);
		printf("after while : i2 = %d\n",i2);
		
		printf("after while : *s1++ = %c\n",*s1++);
		s1=s1-1; */
		if (*s1++ == '=') 
		{
			
		//	printf("after while if : i2 = %d\n",i2);
			return(i2);
		}
		//printf("after if: *s1 = %c\n",*s1);
		
		
		 
	}
	 if (*s1 == '\0' && env_get_char(i2-1) == '=')
		return(i2);
	 
	return(-1);
}

char env_get_char (int index)
{
	char c;

	c = env_get_char_init(index);

	return (c);
}

static char env_get_char_init (int index)
{
	char c;
	//自己设置一个envirenment[]数组
	char default_environment[] = {"a=1\0bc=3\0bd=45\0"};
	c = default_environment[index];

	return (c);
}

对于我这份代码
编译之后就 ./a.out bc
传参进去测试,得到返回值k是等于7,再对照environment数组,
第7个元素是3,到时候再把3put出来,就变成了bc=3实现了env的打印。

总结
当你看懂了的时候会觉得这不难,但是当你看不懂的时候觉得很难,难点就在于 *s1++,还有while循环、if循环,尽管只有一句语句,但是就是少了{}也迷惑了我很久,最终是自己改了代码测试过发送加上之后没错,把层次捋清楚,再查*p++,得到正确的执行步骤。

用到的测试的方法有:
方法1.自己把代码抽出来,然后编译测试
方法2.直接改源码然后烧录进去看结果。

最终把这个do_printenv给看懂看透了。
以后遇到相关的字符串解析的话可以利用uboot中的do_printenv的解析方法。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值