开源代码就是开源代码,不是工程代码;
今天在看x264的 x264_cqm_init 这个函数的代码时,发现里面有个坑;
先来看下 x264_h 里面有这样几个变量:
/* quantization matrix for decoding, [cqm][qp%6][coef] */
int (*dequant4_mf[4])[16]; /* [4][6][16] */
int (*dequant8_mf[2])[64]; /* [2][6][64] */
/* quantization matrix for trellis, [cqm][qp][coef] */
int (*unquant4_mf[4])[16]; /* [4][52][16] */
int (*unquant8_mf[2])[64]; /* [2][52][64] */
/* quantization matrix for deadzone */
uint16_t (*quant4_mf[4])[16]; /* [4][52][16] */
uint16_t (*quant8_mf[2])[64]; /* [2][52][64] */
uint16_t (*quant4_bias[4])[16]; /* [4][52][16] */
uint16_t (*quant8_bias[2])[64]; /* [2][52][64] */
在 x264_cqm_init 中 有这样的代码;
for( int i = 0; i < 4 + num_8x8_lists; i++ )
{
int size = i<4 ? 16 : 64;
int j;
for( j = (i<4 ? 0 : 4); j < i; j++ )
if( !memcmp( h->pps->scaling_list[i], h->pps->scaling_list[j], size*sizeof(uint8_t) ) )
break;
if( j < i )
{
h-> quant4_mf[i] = h-> quant4_mf[j];
h->dequant4_mf[i] = h->dequant4_mf[j];
h->unquant4_mf[i] = h->unquant4_mf[j];
}
else
{
CHECKED_MALLOC(udctcoef (*)[16], h-> quant4_mf[i], (QP_MAX+1)*size*sizeof(udctcoef) );//实际跟踪发现,i会等于4;而 quant4_mf 长度明确定义为4,这岂不是越界了?我准备怀疑我的C语言水平了
CHECKED_MALLOC(int (*)[16], h->dequant4_mf[i], 6*size*sizeof(int) );
CHECKED_MALLOC(int (*)[16], h->unquant4_mf[i], (QP_MAX+1)*size*sizeof(int) );
}
.
.
.
}
在后面对 h->quant4_mf 的访问过程如下
h->quant4_mf[i_list][q][i] = j = SHIFT(quant4_mf[i_list][q%6][i], q/6 - 1);
其中 i_list 范围是 0-3;这里的做法和定义是一致的;
经过仔细地研究代码,发现奥秘是,在上面分配内存的过程中,在一个循环内,实际上是先后给 unquant4_mf[4] 和 unquant8_mf[2] 申请内存和设置内存地址;
num_8x8_lists 实际是 2, 也就是循环的前4次是处理 unquant4_mf[4], 后两次是处理 unquant8_mf[2];
这也就是在 x264_h 相关变量这么定义的原因;
对于其余几个类似变量也是同样的情形。
所以,x264_h 结构体里面的定义 有些地方还真不是可以随便改动的,弄不好就会踩到坑;
这里也同时提示了 指针的特殊用法;
{
unsigned char v3[2][2][3][4] =
{
{
{{1,2,3,4},{5,6,7,8},{9,10,11,12}},
{{13,14,15,16},{17,18,19,20},{21,22,23,24}}
},
{
{{1,2,3,4},{5,6,7,8},{9,10,11,12}},
{{13,14,15,16},{17,18,19,20},{21,22,23,24}}
}
};
unsigned char (*p3[2])[2][3][4];
//here
//p3[0] = p[1] = 0xcccccccc
int d0 = 1;//0-1
p3[d0] = (unsigned char (*)[2][3][4])v3[0];
int d1/*0-1*/, d2/*0-2*/, d3/*0-3*/;
//visit [1][2][3]
d1 = 1, d2 = 2, d3 = 3;
printf("p3[%d][0][%d][%d][%d]=%d\n", d0, d1, d2, d3, p3[d0][0][d1][d2][d3]);
//or printf("p3[%d][0][%d][%d][%d]=%d\n", d0, d1, d2, d3, (*p3[d0])[d1][d2][d3]);
//visit [1][3][2], offset = 1*3*4 + 3*4 + 2; actually visit v3[1][0][0][2]
d1 = 1, d2 = 3, d3 = 2;
printf("p3[%d][0][%d][%d][%d]=%d\n", d0, d1, d2, d3, p3[d0][0][d1][d2][d3]);
//or printf("p3[%d][0][%d][%d][%d]=%d\n", d0, d1, d2, d3, (*p3[d0])[d1][d2][d3]);
//usage in x264
int 16x = 64;
unsigned char (*p4[4])[16];
p4[3] = malloc(16 * 16x);
//visit p4[3][2][5], offset is 2*15 + 5;
printf("p4[3][2][5]=%d\n", p4[3][2][5]);
}