OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 10578|回复: 20

stm32f4 关于strlen无法准确获取char*长度的问题

[复制链接]

1

主题

12

帖子

0

精华

新手上路

积分
27
金钱
27
注册时间
2017-6-16
在线时间
6 小时
发表于 2017-6-16 10:05:00 | 显示全部楼层 |阅读模式
1金钱
不多说废话了,直接上代码

[mw_shl_code=c,true]
u8 tcp_send(void)
{
        u8 err;
        u8 *msg = OSQPend(q_msg,0,&err);
        if (msg!=NULL){
                u32 len = strlen((char *) msg);
                printf("%d\r\n",len);
                err = netconn_write(tcp_clientconn, msg, len, NETCONN_COPY);
                if(err != ERR_OK){
                        myfree(SRAMIN,msg);
                        printf("发送失败\r\n");
                        return 0;
                }
        } else {
                printf("%s\r\n","等待数据");
        }
        myfree(SRAMIN,msg);
        return 1;
}
[/mw_shl_code]

其中len的获取在1毫秒的发送状况下无法准确的获取长度,并且在出现该情况以后单条发送依然存在该问题,
下面是我发送的数据(每行数据以0D 0A结尾)

通信数据

通信数据


得出来的len都是30,即全是第一组数据的长度

若我使用自己编写的以0D为结尾获取长度的函数,则能够准确获取其长度如下:
[mw_shl_code=c,true]
u8 getSize(u8 *msg){
        u8 len=0;
        while (*msg++!='\r') len++;
        return len;
}
[/mw_shl_code]

希望有高手可以给我解答下,这到底是什么原因造成的

最佳答案

查看完整内容[请看2#楼]

标准C字符串是什么意思知道吗,以'\0'结尾的。你发送的字符串没有以'\0'结尾,用strlen读到的字符串长度自然会大很多,因为它会一直搜索直到找到'\0'。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

347

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
2082
金钱
2082
注册时间
2014-12-19
在线时间
711 小时
发表于 2017-6-16 10:05:01 | 显示全部楼层
标准C字符串是什么意思知道吗,以'\0'结尾的。你发送的字符串没有以'\0'结尾,用strlen读到的字符串长度自然会大很多,因为它会一直搜索直到找到'\0'。
回复

使用道具 举报

1

主题

12

帖子

0

精华

新手上路

积分
27
金钱
27
注册时间
2017-6-16
在线时间
6 小时
 楼主| 发表于 2017-6-16 10:50:56 | 显示全部楼层
lvehe 发表于 2017-6-16 10:23
标准C字符串是什么意思知道吗,以'\0'结尾的。你发送的字符串没有以'\0'结尾,用strlen读到的字符串长度自 ...

好吧,我把字符串赋值那部分代码也粘上吧
[mw_shl_code=c,true]
u8 find(u8 *msg,u8 err,u32 data_len)
{
        u32 i=0,start=0;
        u8 len=0;
        u8* msg_data;
        if (data_len>0){
                do{
                        if (*(msg+i) == '\r' & *(msg+i+1) == '\n'){               
                                msg_data = mymalloc(SRAMIN,len+1);                               
                                mymemcpy(msg_data,msg+start,len+1);
                                putTCPQmsg(msg_data,err);
                                i++;
                                start = i + 1;
                                len=0;
                        } else {
                                len++;
                        }
                }while(i++<data_len-1);
        }
        return 0;
}
[/mw_shl_code]
然后发现3ms为间隔发送的时候不会出这个问题,
1ms为间隔发送的时候一开始也不出这个问题,随着时间的延长才会出现
回复

使用道具 举报

1

主题

12

帖子

0

精华

新手上路

积分
27
金钱
27
注册时间
2017-6-16
在线时间
6 小时
 楼主| 发表于 2017-6-16 10:58:56 | 显示全部楼层
一段段贴代码太麻烦了,直接打包上传了,欢迎高手测试,希望能得到解答,板子是stm32f407zgt的
project7z.zip (3.3 MB, 下载次数: 82)
回复

使用道具 举报

2

主题

59

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2017-6-13
在线时间
10 小时
发表于 2017-6-16 15:40:21 | 显示全部楼层
简单来说就是给数组赋值字符串是要特殊注意结尾的'\0'的;
u8 dataBuf[3];dataBuf[0]='A';dataBuf[1]='B';dataBuf[2]='\0'; 那么strlen(dataBuf)=2;
如果dataBuf[3]='C';那么strlen(dataBuf)>=3的;是个不确定的值。
回复

使用道具 举报

1

主题

12

帖子

0

精华

新手上路

积分
27
金钱
27
注册时间
2017-6-16
在线时间
6 小时
 楼主| 发表于 2017-6-16 16:10:34 | 显示全部楼层
335920284 发表于 2017-6-16 15:40
简单来说就是给数组赋值字符串是要特殊注意结尾的'\0'的;
u8 dataBuf[3];dataBuf[0]='A';dataBuf[1]='B'; ...

是不是说强制转换的(char *)msg的字符串也是需要后面加上'\0'才能保证strlen读取出来的长度是3?

我在实际测试的时候是对TCP数据包的粘包现象进行拆包处理的,每个包以\r\n为结尾,每次发送的数据是应拆成3个数据包然后依次加入消息队列的,

当发送的间隔为1-2ms时,3w条后会出现该现象,3w条前不会,而当发送间隔为3ms及更长时(也就是  写入消息队列速率=读取消息队列速率  的时候)在2亿byte的数据通信中不会出现这种现象,这是由于什么原理呢?
回复

使用道具 举报

2

主题

59

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2017-6-13
在线时间
10 小时
发表于 2017-6-16 17:47:46 | 显示全部楼层
你这个比较复杂了,描述的不清楚,程序里判断下吧,出问题的时候把相关数据打印出来仔细分析下。
回复

使用道具 举报

2

主题

59

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2017-6-13
在线时间
10 小时
发表于 2017-6-16 17:49:04 | 显示全部楼层
TCP粘包、断包都可能出现 建议加个数据包头,用几个字节表示长度,这样处理起来比较好吧。
回复

使用道具 举报

1

主题

12

帖子

0

精华

新手上路

积分
27
金钱
27
注册时间
2017-6-16
在线时间
6 小时
 楼主| 发表于 2017-6-17 08:17:21 | 显示全部楼层
335920284 发表于 2017-6-16 17:49
TCP粘包、断包都可能出现 建议加个数据包头,用几个字节表示长度,这样处理起来比较好吧。

先谢谢你了,不过还有些问题。

在程序里加入了判断后,发现添加进消息队列前输出的字符串是正确的,在另一个任务中取出后发现strlen字符串的长度都变成了最长包的长度了

还有我做的主要就是粘包测试,发送的数据本来就是模拟粘包的,目前断包的情况并没有出现,粘包的拆分也没问题,不过从消息队列取出后字符串的长度获取会出现问题,测试过程中觉得ucosii的消息队列并没什么问题,应该就是在强制转换取数据类型或者读取长度时出了问题,并且之后我再单条发送的话长度获取一直存在问题,一直都是最长的数据长度,怀疑是RAM内某些地方乱了,但是实力有限,没办法再进一步去做问题的分析了,能给我解答下吗?
回复

使用道具 举报

2

主题

59

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2017-6-13
在线时间
10 小时
发表于 2017-6-19 10:00:44 | 显示全部楼层
在给消息队列赋值时,先做清零操作试试吧
回复

使用道具 举报

1

主题

12

帖子

0

精华

新手上路

积分
27
金钱
27
注册时间
2017-6-16
在线时间
6 小时
 楼主| 发表于 2017-6-19 17:51:29 | 显示全部楼层
本帖最后由 山丨海 于 2017-6-19 17:59 编辑

我的问题还没有解决,为何结贴了?,我试着去做测试,发现了出现问题的地方,并不是在强制转换和strlen函数,而是从缓冲区读出来时就乱了,并且继续测试,发现tcp通信时发送定长的数据没有问题,但是若下一条发送的数据长度+1或者长度不变内容变了,也没问题,若是-1则会发现还是原来的数据长度,分别用网口助手和串口助手对各个阶段进行了测试,确实是实际出现的问题。若真的是结贴了,那我就重新去悬赏。
回复

使用道具 举报

1

主题

12

帖子

0

精华

新手上路

积分
27
金钱
27
注册时间
2017-6-16
在线时间
6 小时
 楼主| 发表于 2017-6-19 17:52:39 | 显示全部楼层
本帖最后由 山丨海 于 2017-6-19 18:00 编辑
335920284 发表于 2017-6-19 10:00
在给消息队列赋值时,先做清零操作试试吧

请看下我11L的回复,定位到了出现问题的地方,在消息队列并没有出现该问题,不知道为何原子哥给我结贴了,谢谢,并且加上了'\0'也一样,标准c字符串的结构学过计算机的都知道,2L的回复并不能解决我实际出现的问题
回复

使用道具 举报

0

主题

145

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
366
金钱
366
注册时间
2017-6-19
在线时间
55 小时
发表于 2017-6-19 18:14:17 | 显示全部楼层
打个断点仿一下不就知道了
回复

使用道具 举报

1

主题

12

帖子

0

精华

新手上路

积分
27
金钱
27
注册时间
2017-6-16
在线时间
6 小时
 楼主| 发表于 2017-6-20 08:55:56 | 显示全部楼层
本帖最后由 山丨海 于 2017-6-20 08:58 编辑

这次准确定位到了故障点,出现在了
[mw_shl_code=c,true]
u8 find(char *msg,u8 err,u32 data_len)
{
        u32 i=0,start=0;
        u8 len=0;
        char *msg_data;
        if (data_len>0){
                do{
                        if (*(msg+i) == '\r' & *(msg+i+1) == '\n'){               
                                msg_data = mymalloc(SRAMIN,len);                //可能故障点               
                                mymemcpy(msg_data,msg+start,len);                //可能故障点

                                printf("%s\r\n",msg);
                                printf("%s\r\n",msg_data);
                                printf("%d\r\n",len);
                                putTCPQmsg(msg_data,err);
                                i++;
                                start = i + 1;
                                len=0;
                        } else {
                                len++;
                                if (len > 30) break;
                        }
                }while(i++<data_len-1);
        }
        return 0;
}
[/mw_shl_code]

输出的结果为:
第一次发送的数据:
QQ截图20170620085247.png
第二次去掉一部分包发送的数据:
QQ截图20170620085334.png

这是由于什么原因引起的?
想尝试使用系统自带的malloc,但是一直编译通过不了,勾选了微库后发现ucosii运行不了,求助

回复

使用道具 举报

1

主题

12

帖子

0

精华

新手上路

积分
27
金钱
27
注册时间
2017-6-16
在线时间
6 小时
 楼主| 发表于 2017-6-20 10:25:06 | 显示全部楼层
OK,自己解决了,重写了malloc.c里的mymemcpy和myfree成功解决问题!!
回复

使用道具 举报

17

主题

84

帖子

0

精华

初级会员

Rank: 2

积分
108
金钱
108
注册时间
2015-11-30
在线时间
22 小时
发表于 2017-6-20 10:29:27 | 显示全部楼层
size_t strlen(const char * s)
{
        const char *sc;

        for (sc = s; *sc != '\0'; ++sc)
                /* nothing */;
        return sc - s;
}

strlen的源码,你试试这个!
回复

使用道具 举报

3

主题

347

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
2082
金钱
2082
注册时间
2014-12-19
在线时间
711 小时
发表于 2017-6-20 10:30:25 | 显示全部楼层
山丨海 发表于 2017-6-20 10:25
OK,自己解决了,重写了malloc.c里的mymemcpy和myfree成功解决问题!!

发代码上来如何,感觉你还是没有弄懂真正的故障原因
回复

使用道具 举报

3

主题

21

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-14
在线时间
18 小时
发表于 2017-6-20 11:22:12 | 显示全部楼层
直接free msg 啊,不会内存泄露吗?
回复

使用道具 举报

1

主题

12

帖子

0

精华

新手上路

积分
27
金钱
27
注册时间
2017-6-16
在线时间
6 小时
 楼主| 发表于 2017-6-20 13:34:58 | 显示全部楼层
本帖最后由 山丨海 于 2017-6-20 13:44 编辑

RAM没清掉,试着用lwip里面的内存管理,然后成功了,而且lwip的netbuf也存在类似的问题,不过每次只会出现一次,再把这一次给处理了就ok了
回复

使用道具 举报

1

主题

12

帖子

0

精华

新手上路

积分
27
金钱
27
注册时间
2017-6-16
在线时间
6 小时
 楼主| 发表于 2017-6-20 13:37:49 | 显示全部楼层
本帖最后由 山丨海 于 2017-6-20 14:00 编辑

每次将原来的mymemcpy里面的src和des分别输出来就知道了原因哦,对了,然后再每次将两个串的拷贝长度-1后拷贝,输出来结果也是正确的
回复

使用道具 举报

1

主题

12

帖子

0

精华

新手上路

积分
27
金钱
27
注册时间
2017-6-16
在线时间
6 小时
 楼主| 发表于 2017-6-20 14:04:36 | 显示全部楼层
brave_dancing 发表于 2017-6-20 10:29
size_t strlen(const char * s)
{
        const char *sc;

嗯,strlen这个函数没有问题之前是脑子晕圈了才会认为是这里的问题;
<br>
u8 getSize(u8 *msg){
        u8 len=0;
        while (*msg++!='\r') len++;
        return len;
}
这个函数就是仿照着写的
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-17 16:04

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表