使用opencv传中文文件崩溃

这个问题经过我的调试发现:
  程序是在
while (*at && !isdigit(*at)) at++;  
这个语句时crash的,但是跟进去是isdigit的问题,因为变量at的声明是char* at;  当at指向一个中文路径的时候,在传递给 isdigit时,*at类型很明显,隐式转换成为了int,因为  isdigit(int c)是这样声明的。所以这个时候一下子int c变成了一个负数:0xffffffb2,然后再往下跟进执行到 _ASSERTE((unsigned)(c + 1) <= 256);这个语句才崩溃的,因为强制转换成无符号的int,变成了一个很大的正数。明显不满足断言条件,所以程序当然crash了。
 
以上的crash情况只有在Debug版本才会crash,Release版本就不会出问题。原因已经在微软带的CRT库的源码中看出来了
 
结论:
   应该是我们使用的问题,中文windows默认的locale是GB2312的,我们很可能却调用ASCII版本的 isdigit函数(所以遇到中文立即crash),这已经不符合逻辑了,咱不可能手动去改变locale。
 
下面是opencv源码中造成崩溃的函数源码(注意第三十行造成crash的语句):
 1 static char* icvExtractPattern(const char *filename, unsigned *offset)
 2 {
 3     char *name = (char *)filename;
 4 
 5     if( !filename )
 6         return 0;
 7 
 8     // check whether this is a valid image sequence filename
 9     char *at = strchr(name, '%');
10     if(at)
11     {
12         int dummy;
13         if(sscanf(at + 1, "%ud", &dummy) != 1)
14             return 0;
15         name = strdup(filename);
16     }
17     else // no pattern filename was given - extract the pattern
18     {
19         at = name;
20 
21         // ignore directory names
22         char *slash = strrchr(at, '/');
23         if (slash) at = slash + 1;
24 
25 #ifdef _WIN32
26         slash = strrchr(at, '\\');
27         if (slash) at = slash + 1;
28 #endif
29 
30         while (*at && !isdigit(*at)) at++;
31 
32         if(!*at)
33             return 0;
34 
35         sscanf(at, "%u", offset);
36 
37         int size = (int)strlen(filename) + 20;
38         name = (char *)malloc(size);
39         strncpy(name, filename, at - filename);
40         name[at - filename] = 0;
41 
42         strcat(name, "%0");
43 
44         int i;
45         char *extension;
46         for(i = 0, extension = at; isdigit(at[i]); i++, extension++)
47             ;
48         char places[10];
49         sprintf(places, "%dd", i);
50 
51         strcat(name, places);
52         strcat(name, extension);
53     }
54 
55     return name;
56 }

 

 

 

下面是个最小的崩溃场景例子:

 1 #include<ctype.h>
 2 #include<stdio.h>
 3 
 4 
 5 int main(){
 6 
 7     char *pPath = "测试视频";
 8     #if defined (_DEBUG)
 9     if(!isdigit(*pPath)){
10         printf("its not digit\n");
11     }
12   #else
13     if(!iswdigit(*pPath)){
14         printf("Release its not digit\n");
15     }
16   #endif
17     return 0;
18 }

 

 

 

 

 

 

以下是一个测试:

 1 #include <stdio.h>
 2 #include <Windows.h>
 3 
 4 int NarrowChar() {
 5     char *pcAlpha = "";
 6     printf("pcAlpha  = 0x%08X!\n", *pcAlpha); //0xFFFFFFB0
 7     return 0;
 8 }
 9 
10 int WideChar() {
11     //wchar_t *pwcAlpha = L"A";
12     wchar_t *pwcAlpha = L"";
13     printf("pwcAlpha  = 0x%08X!\n", *pwcAlpha); //0x0000554A    UTF-16-little-endian
14     //wprintf(L"pwcAlpha  = 0x%08X!\n", *pwcAlpha); //0x0000554A
15     return 0;
16 }
17 
18 int main(void) {
19      NarrowChar();
20      WideChar();
21 
22      return 0;
23 }

由以上可以看出来,字符串这个前缀‘L’实质上是对字符串从ANSI字符集转换为Unicode字符集,也就是UTF-16编码。如果不加这个L前缀就是ANSI/ASCII字符集。

 

 

以上的问题我前博文已经研究过了。

 

################################update#############################

 

结论:

 

经过调试测试,其实就是cvCreateFileCapture函数返回失败的原因,在opencv 2.4.9和opencv2.4.10中就有问题,就是都返回失败,而2.4.6就不会

 

 

 

references:

http://www.cppblog.com/luonjtu/archive/2009/03/13/76332.html

http://comments.gmane.org/gmane.comp.lib.opencv.devel/1274

http://msdn.microsoft.com/en-us/library/windows/desktop/ff381407(v=vs.85).aspx

http://blog.csdn.net/xiaobai1593/article/details/7063535

http://stackoverflow.com/questions/8032080/how-to-convert-char-to-wchar-t

 
posted @ 2014-12-18 10:47  foo__hack  阅读(793)  评论(0编辑  收藏  举报