请选择 进入手机版 | 继续访问电脑版

C++编程

 找回密码
 立即注册

QQ登录

只需一步,快速开始

楼主: ID紫麒麟

紫麒麟笔记_1杂乱

[复制链接]

18

主题

225

帖子

971

积分

高软

Rank: 4

积分
971
 楼主| 发表于 2016-5-13 16:39:07 | 显示全部楼层
avio_reading.c

extern "C"{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libavutil/file.h>
};
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avcodec.lib")
struct buffer_data {
    uint8_t *ptr;        //文件中对应位置指针
    size_t size; ///文件当前指针到末尾数据大小
};
//将文件中数据拷贝至缓冲区,同时文件指针位置偏移,数据大小改变
static int read_packet(void *opaque, uint8_t *buf, int buf_size){
    struct buffer_data *bd = (struct buffer_data *)opaque;
    buf_size = FFMIN(buf_size, bd->size);
    printf("ptr:%p size:%u\n", bd->ptr, bd->size);
    /* copy internal buffer data to buf */
    memcpy(buf, bd->ptr, buf_size);
    bd->ptr  += buf_size;
    bd->size -= buf_size;
    return buf_size;
}
int main(int argc, char *argv[]){
        AVFormatContext*fmt_ctx=NULL;
        AVIOContext*avio_ctx=NULL;
        uint8_t*buffer=NULL;
        uint8_t*avio_ctx_buffer=NULL;
        size_t buffer_size,avio_ctx_buffer_size=4096;
        const char*input_filename="test.mkv";
        struct buffer_data bd={0};
        int ret=0;
        //注册所有支持的代码,能使用的都使用,方便,也可以按需注册自己所需的部分
        av_register_all();
        //类似于UNIX下的mmap函数所实现的功能,返回文件开始指针,文件大小
        //文件过大,有3,4个G也能正常使用??
        //经测试,并不耗内存,可视为UNIX下的文件映射
        ret=av_file_map(input_filename,&buffer,&buffer_size,0,NULL);
        if(ret<0){
                printf("av_file_map Err:%d\n",ret);
                goto end;
        }
//        printf("filesize:%d\n",buffer_size);
        bd.ptr=buffer;
        bd.size=buffer_size;
        //初始化文件格式的结构体,就是分配内存,以后获取或设置编码格式都可以用这结构体管理,应该是当中的成员
        if(!(fmt_ctx=avformat_alloc_context())){
                //失败返回内存错误ENOMEM
                ret=AVERROR(ENOMEM);
                goto end;
        }
        //分配内存,可以自己设置缓冲大小
        if(!(avio_ctx_buffer=(uint8_t*)av_malloc(avio_ctx_buffer_size))){
                ret=AVERROR(ENOMEM);
                goto end;
        }
        //估计跟内存管理有关,avio_ctx_buffer是缓冲区,avio_ctx_buffer_size是缓冲区大小
        //bd是文件,read_packet是读取函数
        //avio_ctx->buffer=avio_ctx_buffer
        if(!(avio_ctx=avio_alloc_context(avio_ctx_buffer,avio_ctx_buffer_size,0,
                &bd,&read_packet,NULL,NULL))){
                ret=AVERROR(ENOMEM);
                goto end;
        }
        //指针位置一样
        //printf("%p %p\n",avio_ctx_buffer,avio_ctx->buffer);
        //设置IO管理
        fmt_ctx->pb=avio_ctx;
        //跟metadata中avformat_open_input(&fmt_ctx,filename,NULL,NULL)等效
        //这里都是自已去配置初始化相关信息,最后也要自己去清理
        ret=avformat_open_input(&fmt_ctx,NULL,NULL,NULL);
        if(ret<0){
                printf("Open Err\n");
                goto end;
        }
/*
//metadata中代码在这一样可以用,输出一样,主要输出格式
        AVDictionaryEntry*tag=NULL;
        while ((tag=av_dict_get(fmt_ctx->metadata,"",tag,AV_DICT_IGNORE_SUFFIX))){
                printf("%s=%s\n",tag->key,tag->value);
        }
*/
        ret=avformat_find_stream_info(fmt_ctx,NULL);
        if(ret<0){
                printf("Could not find stream information\n");
                goto end;
        }
        //输出基本信息,这里input_filename,只是用来显示文件名,无实际用处
        //可随意换成其他字符串,不影响
        //包含av_dict_getn内容,还有音视频编码信息
        av_dump_format(fmt_ctx, 0, input_filename, 0);
end:
        avformat_close_input(&fmt_ctx);
        if (avio_ctx) {
                //应该就是av_free(&avio_ctx_buffer),但位置不对
                //两者相差0x1960
                //printf("%p %p\n",avio_ctx_buffer,avio_ctx->buffer);
        av_freep(&avio_ctx->buffer);
        av_freep(&avio_ctx);
    }
        av_file_unmap(buffer, buffer_size);
        printf("RET:%d\n",ret);
        system("PAUSE");
        return ret;
}
回复 支持 反对

使用道具 举报

18

主题

225

帖子

971

积分

高软

Rank: 4

积分
971
 楼主| 发表于 2016-5-16 11:42:55 | 显示全部楼层
回复 支持 反对

使用道具 举报

18

主题

225

帖子

971

积分

高软

Rank: 4

积分
971
 楼主| 发表于 2016-5-17 13:11:20 | 显示全部楼层

昨天晚上
我喝大了
你说再拿一杯
就回家睡了
我头疼欲裂
就快要吐了
也许昨天的酒
掺了很多
或许心里的事儿
咱还没放过
这个就是
我们的生活
喝点儿小酒
就想找人述说
不得意的事儿
你跟我说
反正明天了
咱还得正常的活
姑娘跟我说
她和男友四年的往事
这么多年的任性
终于能告一段落
爱情里没有谁对谁错
没有特别的难过
看看周围的谁
没被它伤过
喔哦~
没被它伤过
哦~~~
这就是生活
面包和爱情的故事
你知道的太多
哦~~~
这就是生活
这一场宿醉
能换来明天平静的过
哦~~~
这就是生活
它吆五喝六儿
你还得笑脸迎合
哦~~~
生活往往幽默
不要太装(作)
不要太死磕
<独白>
内天一个哥们儿跟我说他失业了
然后
内天一个姐们儿跟我说她失恋了
我说生活往往就是这样
去看看周围
周围的这些人
有谁
没有被它
真正的
真正的伤过
这就是生活
回复 支持 反对

使用道具 举报

18

主题

225

帖子

971

积分

高软

Rank: 4

积分
971
 楼主| 发表于 2016-5-19 13:55:29 | 显示全部楼层
本帖最后由 ID紫麒麟 于 2016-5-19 14:00 编辑

求答案 ?
一筐鸡蛋:
1个1个拿,正好拿完。
2个2个拿,还剩1个。
3个3个拿,正好拿完。
4个4个拿,还剩1个。
5个5个拿,还剩1个
6个6个拿,还剩3个。
7个7个拿,正好拿完。
8个8个拿,还剩1个。
9个9个拿,正好拿完。

问筐里有多少鸡蛋?

第一反应答案:

#include <iostream>
using namespace std;
int main()
{
        int n;
        printf("输入最大篮子存放鸡蛋的个数\n");
        scanf(" % d ", &n);

        while (n--> 0)
               
                if (n % 1 == 0 && n % 2 == 1 && n % 3 == 0 && n % 4 == 1 && n % 5 == 1 && n % 6 == 3
                           && n % 7 == 0 && n % 8 == 1 && n % 9 == 0)
                        printf("%d    ", n);
        

return 0;
}



实际上:
(0x9 == (n | 0xf)) && 3 == (n % 6) && 1 == (n % 5) && 0 == (n % 7)
这个判断足够了


回复 支持 反对

使用道具 举报

18

主题

225

帖子

971

积分

高软

Rank: 4

积分
971
 楼主| 发表于 2016-5-19 17:22:34 | 显示全部楼层
CString的Format针对uint64_t似乎有bug?今天听说的。

1、CString类的MakeLower (),大写转小写。因为产品中,是安卓和ios通过底层通信协议往服务器端传数据,但安卓的版本实在太多太杂,实在没有办法控制编码格式。问题是,VS2008里,UTF-8的某些敏感字符,一小写转换,它直接崩溃。这种鸟问题,测都没法测。被割了几天找不着原因,后来直接用CharLower API接口解决。

2、MFC的标准类中,关于字符串操作的例如Format以及sprintf实在没有安全性可言,特别是在线程中。按照设计,本来是按字日期字符串来传输的,但这些鸟残Class函数,导致了某些DLL不可预知的错误,虽然不崩溃,但运行结果不正常。实在没有办法,后来按整型数字来处理解决。

上面这两个问题还真得注意啊。
回复 支持 反对

使用道具 举报

18

主题

225

帖子

971

积分

高软

Rank: 4

积分
971
 楼主| 发表于 2016-5-30 17:09:30 | 显示全部楼层
看到了四句话:

网络游戏中广泛应用的航位推测法美国军方也在使用
游戏中的自动寻路算法,在机器人和自动驾驶中也有应用
游戏中的决策与博弈论也有关联
游戏服务器集群之间的负载均衡与一致性,和现在热门的大数据息息相关。
回复 支持 反对

使用道具 举报

18

主题

225

帖子

971

积分

高软

Rank: 4

积分
971
 楼主| 发表于 2016-6-1 16:41:52 | 显示全部楼层
突然想到VR产生眩晕感的事情了,我认为眩晕是因为VR呈现的东西在人的潜意识分析面前还不够强大。
不管是晶状体调节,视觉焦点,人体动作跟画面不匹配还是说余辉之类的问题。
传输速度分析速度应该依然是瓶颈的吧。
回复 支持 反对

使用道具 举报

18

主题

225

帖子

971

积分

高软

Rank: 4

积分
971
 楼主| 发表于 2016-6-2 11:28:41 | 显示全部楼层
本帖最后由 ID紫麒麟 于 2016-6-2 11:33 编辑

今天被一个人问了一个特别简单的问题。。。。。
给出一个函数,去判断一个月总共多少天?

随手写一个吧:
DAYS[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
int CountDays(int year, int month) {
    assert(month > 0 && month < 13);
    if(2 == month) {
     if (0 == (year & 0x5))
      return 29;
     else
      return 28;
    } else {
    return DAYS[month];
    }
}


int CountDays(int year, int month) {
    assert(month > 0 && month < 13);
    switch (month) {
    case 1: case 3: case 5: case 7: case 8: case 10: case 12: return 31;
    case 4: case 6: case 9: case 11: return 30;
    case 2:
     if (0 == (year & 0x5))
      return 29;
     else
      return 28;
    }
}
编码规范之类的仁者见仁智者见智,规范的种类也挺多的,什么匈牙利命名法,还有Google的规范。反正是比较多吧。
回复 支持 反对

使用道具 举报

18

主题

225

帖子

971

积分

高软

Rank: 4

积分
971
 楼主| 发表于 2016-6-6 11:11:17 | 显示全部楼层
最近对内存操作有一点儿兴趣

写在前头:
我不能保证此文中,我的观点和理解全是对的,这也不是一篇教学贴,只是我偶尔突发奇想了几个特殊的场景,然后用实验得到结果,对结果进行分析,遂成此文。所以文中肯定存在错误,我也没想到会上首页,引来众人围观。
最后,欢迎拍砖,我觉得错了不要紧,改就是了,最惨的是不知道自己错在哪。

首先看一下man手册中的定义,

void *malloc(size_t size);
向系统申请size个Bytes长的连续内存,返回一个void类型的指针,指向这块儿内存的首地址。这块申请到的内存是不洁的(也就是非全0x00,内容可以是任意的,随机的)
如果size的值是0,那么返回的指针要么是指向NULL,要么是指向一个unique的地址,这个地址是可以被free释放的。(这里的解释是有问题的,例子(8)会证明)

void free(void *ptr);
释放ptr指向的内存空间,ptr必须是之前调用过malloc,calloc,realloc这三个函数返回的,否则,如果free(ptr)已经执行过了,而又执行一次,那么会导致意外发生(undefined behavior occurs.),如果ptr指向的是NULL,则不会做任何操作。

(1)假设有
char *p = NULL;
p = (char*)malloc(0);
那么p获得的内存块的长度到底是多少?能否往里面写入数据?
答:不妨用这段代码来测试:
int main(int argc, char **argv)
{
    char *value = NULL;   
    char *ori   = NULL;
    value = malloc(0);
    ori   = value;
    printf("value[0] is [%c]\n", *value);
    while(1) {
        *value = 'a';
        value++;
        printf("value len [%d]\n", strlen(ori));
    }
}
这段代码结果如下所示:Fedora14:
[michael@localhost mem-test]$ ./a.out     
value[0] is []
yydebug:[./mem-test.c]:[34]:value len [1]
yydebug:[./mem-test.c]:[34]:value len [2]
yydebug:[./mem-test.c]:[34]:value len [3]
...(省略N行)
yydebug:[./mem-test.c]:[34]:value len [135157]
yydebug:[./mem-test.c]:[34]:value len [135158]
yydebug:[./mem-test.c]:[34]:value len [135159]
Segmentation fault (core dumped)
[michael@localhost mem-test]$
我重新编译、运行了很多次,最后打印结果都是135159;
这个结果证明了malloc(0)返回的指针指向的是一个非NULL的内存地址处,并且该处的值是0x00,并且对于该进程,不仅该处是可写的,而且之后的135159个Bytes也都是可写的,也就是属于这个进程空间。直到最后,可能写到别的进程的空间里面去了,才被内核发来段错误信号,自己结束了。
其实在写该处就已经是内存越界了,往后继续写更加是内存越界,只是刚好那么巧,该处往后的内存块依然是该进程的有效heap区间,所以才没有被内核发段错误,而往往这种情况是最惨的,在实际开发工作中,假设哪天真的出个这情况,又不会被警告,但是却有发现数据被窜改。

(2)假设有

void *p = NULL;
p = malloc(0);
那么稍后p需要用free(p)来释放,以避免内存泄漏吗?
答:不妨用这段代码来测试:
int main(int argc, char **argv)
{
    char *value = NULL;

    while(1) {
        value = (char*)malloc(0);
        printf("value addr [%p]\n", value);
    }
    return 0;
}
结果如下所示:
...(幸亏我及时Ctrl+C停住,运行超过几秒,电脑就会卡爆了)
value addr [0x87aa5c8]
value addr [0x87aa5d8]
value addr [0x87aa5e8]^C
[michael@localhost mem-test]$
从打印看来,虽然是调用malloc(0);,但是每次指向的地址都不同,并且逐渐增大,偏移是0x10,也就是16个字节。
可以不用while(1)来测试,用一个有限的不是很大的值来测试,然后用top命令来观察这个进程的资源使用情况,可以看出a.out消耗的内存在不断增加,所以答案就是,malloc(0)申请的内存,也要通过free()来释放,以避免内存泄漏。

(3)假设有

char *p = NULL;
free(p);
那么会导致进程退出吗?
答案:不会,free(NULL)相当于啥事儿不干。

(4)假设有

char *p = NULL;
while(1) {
    free(p);
}
那么会导致进程退出吗?
答案:不会,进程永远循环在while(1)里面,不会出错退出。

(5)假设有

void *p = NULL;
p = malloc(256);
free(p);
free(p);
那么进程会出错退出吗?
答案:进程会出错退出,打印堆栈信息,提示
[michael@localhost mem-test]$ ./a.out
*** glibc detected *** ./a.out: double free or corruption (fasttop): 0x09dad008 ***
类似的信息。所以已经free掉的内存,除非又申请回来了,否则不能再次去free它,否则进程会出错。

(6)为什么经常有人说free(p);要和p = NULL;一起用,以避免“野指针”的出现?
答案:其实用上面那个例子(5)就能看出,如果free超过1次就会出错,但是从例子(3)和例子(4)可以看出,free(NULL);可以执行任意次都不会出错。所以一般free(p);之后,马上把p指向NULL;,从而即使别人再去执行free(p);也不会出现错误。不仅如此,通过让p指向NULL,也很好的给别人一个提示,你是否对p进行了成功的操作,让别人好判断。不妨看看如下的例子:

void foo(char *in)//你做的功能函数
{
    free(in);   
}
int main(int argc, char **argv)
{
    char *p = NULL;
    p = strdup("hello_world");
    printf("p = [%s], len = [%d]\n", p, strlen(p));
    foo(p); //你同事在调用你的函数

    //感谢@ColoredCotton的贡献
    //由于foo函数的形参是*p,所以无法在foo函数内修改实参指针的指向,所以这的判断总是true
    if (NULL != p) {//他不确定你有木有free(),他还很聪明的做了一个判断
        free(p);
        p = NULL; //他习惯很好,free之后指向NULL
    }
    return 0;
}
假设foo函数是你写的,你同事在调用foo功能的时候,又不确定你是否free了传进去的那块内存,于是他就在调用完foo之后,加了判断,然后执行free,结果他得到的结果是,虽然你free了指针p,但是这仅仅是告诉内核,这块内存我不用了,你可以收回了,值得注意的是,p依然指向这块内存,换句话说也就是指针变量p存的值依然是刚才释放掉的那块内存的首地址。所以你同事的判断得到的结果是true,然后又会执行free(p);结果当然和例子(5)一样了,如下所示:
[michael@localhost mem-test]$ ./a.out
p = [hello_world], len = [11]
*** glibc detected *** ./a.out: double free or corruption (fasttop): 0x09088008 ***
那么“野指针”还可以这样定义,指向所有非法地址(NULL除外)的指针都可以叫野指针。
那么程序应该改成这样较妥:

void foo(char **in)//调用方式应该是传入某个指针的地址
{   
    printf(" &in = [%p], in\'s address\n", &in);
    printf("  in = [%p], in\'s value\n",  in);
    printf(" *in = [%p]\n", *in);
    printf("**in = [%c]\n", **in);
    free(*in); //*in是实参的指针变量p的指向的被分配的内存
    *in = NULL; //使得p指向NULL,也就是修改变量p的值
}
int main(int argc, char **argv)
{
    char *p = NULL;
    p = strdup("hello_world");
    printf("   p = [%s], len = [%d]\n", p, strlen(p));
    printf("  &p = [%p], p\'s address\n", &p);
    printf("   p = [%p], p\'s value\n",  p);
    printf("  *p = [%c], value of addr No.[%p]\n", *p, p);
    foo(&p); //这里应该传入p的地址,即&p

    //感谢@ColoredCotton的贡献
    //而现在,这里的判断就会是false了
    if (NULL != p) { //这里的判断就有意义了
        free(p);
        p = NULL;
    }
    else {
        printf("p is NULL\n");
    }
    return 0;
}
运行一遍,看看打印如何:
[michael@localhost mem-test]$ ./a.out
   p = [hello_world], len = [11]
  &p = [0xbf94014c], p's address
   p = [0x9964008], p's value
  *p = [h], value of addr No.[0x9964008]
&in = [0xbf940130], in's address
  in = [0xbf94014c], in's value
*in = [0x9964008]
**in = [h]
p is NULL
[michael@localhost mem-test]$
我想,根据打印信息来看,没什么需要解释的了。顺便还弄透彻了指针以及函数传参。


(7)刚malloc后,马上就free,然后一直循环,会不会总是申请到同一块内存?

答案:这不是真的。不信?你用这些代码测试一下就知道了:

int main(int argc, char **argv)
{
    char *p = NULL;
    int ra = 0;
    while(1) {
        ra = rand()%100+1; //生成一个1-100之间的随机数
        if (NULL != (p = (char*)malloc(ra))) {
            printf("p addr [%p], ra = [%d]\n", p, ra);
        }
        else {
            return -1;
        }
        free(p);
    }
    return 0;
}
看看打印吧:
p addr [0x8bd8008], ra = [59]
p addr [0x8bd8048], ra = [78]
p addr [0x8bd8008], ra = [41]
p addr [0x8bd8038], ra = [46]
p addr [0x8bd8070], ra = [82]
p addr [0x8bd8008], ra = [62]
p addr [0x8bd8008], ra = [91]
p addr [0x8bd8008], ra = [24]
为什么不会一样呢?这个可以深究一下Linux系统的内存分配方式了,这就涉及到内核了。
回复 支持 反对

使用道具 举报

18

主题

225

帖子

971

积分

高软

Rank: 4

积分
971
 楼主| 发表于 2016-6-6 11:11:34 | 显示全部楼层


(8)malloc(0)返回的真的入man手册所说:要么是NULL,要么是一个unique的pointer?
答案:不妨看下这段代码:

int main(int argc, char **argv)
{
    char *p = NULL;
    char *p0 = NULL;
    int ra = 0;
    while(1) {
        ra = rand()%100+1;
        if (NULL == (p = (char*)malloc(ra))) {
            printf("error occurs\n");
        }
        if (NULL != (p0 = malloc(0))) {
            printf("p0 addr [%p]\n", p0);
        }
        free(p);
        free(p0);
    }
    return 0;
}
打印如下所示:
p0 addr [0x97eb008] #我随便截取了一段打印
p0 addr [0x97eb008]
p0 addr [0x97eb008]
p0 addr [0x97eb040]
p0 addr [0x97eb040]
p0 addr [0x97eb040]
所以从打印看来,我用Fedora14测试的时候,返回的既不是NULL,也不是一个唯一的地址,我现在也迷惑了,man手册中的unique到底应该如何理解。很遗憾man手册说得不太准确。如果你知道为什么,请告诉我,如果我哪一天弄明白了,我会在这里贴出来的。


(9)如果你也和我一样,做了这么多的实验,你是不是发现,malloc得到的地址的值总是大于0x80000000的(32bits机器)?
答案:不好意思,我也不知道为什么,做了好多次,不管如何重新编译、运行,得到的结果都是大于0x80000000的,如果你知道为什么,也请告诉我,如果我哪一天弄明白了,我会在这里贴出来的。
PS:此问题发出后,大家给了很多有用的建议,我也去了解了Linux内存空间布局的相关知识,个人认为比较好的是这篇,不妨移步至此:http://mqzhuang.iteye.com/blog/901602
回复 支持 反对

使用道具 举报

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

本版积分规则

Archiver|手机版|小黑屋|C++编程  

GMT+8, 2019-7-22 19:40 , Processed in 0.078125 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

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