1 av_strdup()
av_strdup() 声明:
- 所属库:libavutil(lavu),lavu是ffmpeg中的功能库,本函数属于内存管理功能
- 头文件:libavutil/mem.h
- 声明:拷贝一份字符串。注意,该函数使用了av_malloc_attrib宏进行了属性修饰,该属性的作用见另外一篇文章
FFMPEG4.1源码分析之 内存管理APIs av_malloc() && av_mallocz()/** * Duplicate a string. * * //入参s指向需要拷贝的字符串 * @param s String to be duplicated * * //返回一个指向新分配的内存,该内存拷贝了一份字符串,如果无法分配出空间,则返回NULL * @return Pointer to a newly-allocated string containing a * copy of `s` or `NULL` if the string cannot be allocated * @see av_strndup() */ char *av_strdup(const char *s) av_malloc_attrib;
av_strdup() 源码:
- 源文件:mem.c
char *av_strdup(const char *s) { char *ptr = NULL; if (s) { // 求取存储字符串的长度,注意c串后的需要"\0",因此需要长度+1 size_t len = strlen(s) + 1; // av_realloc()分配空间,为什么不是av_malloc()? ptr = av_realloc(NULL, len); // 如果空间分配成功,则memcpy进行内存拷贝 if (ptr) memcpy(ptr, s, len); } return ptr; }
-
上述代码相当简单易懂,见代码注释即可
-
问题再于给ptr分配空间的时候为什么不使用av_malloc(),而使用av_realloc()?这里涉及的c库的内存分配函数malloc()和realloc()函数的区别。malloc()是重新分配一块地址,而realloc()是在入参ptr指向的地址空间处进行内存的扩大或者缩小。对于本函数的功能来说,使用av_realloc()传入ptr为NULL,因此与av_malloc()个人感觉是没有太大区别。或许是对c库的内存管理函数还理解不太深刻的缘故。因此,在后续的ffmpeg学习中会专门开个内存管理的专门章节,进一步详细的研究ffmpeg中的内存管理以及对应的底层c库,以及更底层的系统调用sbrk(),brk()等等。
2 av_strndup()
av_strndup() 声明:
- 所属库:libavutil(lavu),lavu是ffmpeg中的功能库,本函数属于内存管理功能
- 头文件:libavutil/mem.h
- 声明:拷贝字串。
重点:入参len指代了结果串的长度,那么需要考虑len与源串长度对比情况,大于,等于,小于的各种情况下都如何处理。/** * Duplicate a substring of a string. * * @param s String to be duplicated * @param len Maximum length of the resulting string (not counting the * terminating byte) * @return Pointer to a newly-allocated string containing a * substring of `s` or `NULL` if the string cannot be allocated */ char *av_strndup(const char *s, size_t len) av_malloc_attrib;
av_strndup() 源码:
- 源文件:libavutil/mem.c
char *av_strndup(const char *s, size_t len) { char *ret = NULL, *end; if (!s) return NULL; end = memchr(s, 0, len); // 计算'\0'的位置 if (end) // 重新计算可拷贝字符串的长度 len = end - s; ret = av_realloc(NULL, len + 1); // 分配内存 if (!ret) return NULL; memcpy(ret, s, len); // 拷贝内存 ret[len] = 0; // 最后一个字节赋值'\0' return ret; // 返回新串地址 }
- 检查参数的有效性:如果源串s是空串,则目的串直接为NULL
- 匹配源串长度与len的大小:memchr()函数提供这样的功能:“C 库函数 void *memchr(const void *str, int c, size_t n) 在参数 str 所指向的字符串的前 n 个字节中搜索第一次出现字符 c(一个无符号字符)的位置”,具体该函数的用法,这儿提供一个很不错的手册类查询网站,提供多种语言的api查询:https://www.runoob.com/。此处,查询0的位置,其实就是字符"\0",C类字符串的结尾。
1)如果返回值不为空,说明len的长度比源串的长度要长,需要重新计算可拷贝的字符串len的长度:len = end - s
2)如果返回值为空,说明len比源串的长度要短,拷贝len个字符是安全的,因此不需要重新计算len - 分配内存,拷贝串,返回新串地址。