Pointer arithmetic in C generated by ida / hexrays decompiler

Please help me understand the following function lines. The loop body does some floating point arithmetic, but why does it cast float pointers to `char *`, and back?

``````if ( CG.blockLength >= 4 )
{
nrLevel = (char *)xTime - (char *)scratch;
v8 = &scratch[CG.blockLength];
v9 = xFreq + 1;
v10 = outBuf + 2;
v7 = 0;
do
{
*(v9 - 1) = xTime[v7];
v7 += 4;
v9 += 4;
*v8 = *(v10 - 2);
v8 += 4;
*(v9 - 4) = *(float *)((char *)v9 + nrLevel - 16);
v10 += 4;
*(v8 - 3) = *(float *)((char *)v9 + (char *)outBuf - (char *)xFreq - 16);
*(v9 - 3) = *(float *)((char *)v10 + (char *)xTime - (char *)outBuf - 16);
*(v8 - 2) = *(v10 - 4);
*(v9 - 2) = xTime[v7 - 1];
*(v8 - 1) = *(v10 - 3);
}
while ( v7 < L - 3 );
}
if ( v7 < L )
{
v11 = &xFreq[v7];
v12 = &xFreq[v7 + L];
v13 = L - v7;
do
{
v14 = *(float *)((char *)v11 + (char *)xTime - (char *)xFreq);
++v11;
*(v11 - 1) = v14;
++v12;
--v13;
*(v12 - 1) = *(float *)((char *)v11 + (char *)outBuf - (char *)xFreq - 4);
}
while ( v13 );
}
``````

Full function are here for quick reference

``````int __cdecl NR_Proc(_NoiseReduction *Q, AudioSignal2_ *signal)
{
float *scratch; // ecx@1
float *v3; // edx@1
float *xTime; // ebx@1
int v5; // esi@1
int v7; // edi@5
float *v8; // ecx@6
float *v9; // eax@6
float *v10; // edx@6
float *v11; // eax@9
float *v12; // edx@9
int v13; // ecx@9
double v14; // st7@10
double v15; // st7@14
float *v16; // eax@14
double v17; // st6@14
double v18; // rt0@15
float *v19; // ecx@16
double v20; // rt1@16
double v21; // st6@16
double v22; // st7@16
bool v23; // zf@16
double v24; // st7@18
double v25; // st6@18
double v26; // st5@18
double v27; // st4@18
double v28; // st3@18
int v29; // ecx@19
unsigned int v30; // edx@19
float *v31; // edi@19
double v32; // st2@21
double v33; // st7@21
double v34; // rtt@21
double v35; // st2@21
double v36; // st6@21
double v37; // rt0@23
double v38; // st2@23
double v39; // st4@23
double v40; // st5@23
double v41; // st2@23
double v42; // rt0@23
double v43; // st2@23
double v44; // rt1@23
double v45; // st2@23
double v46; // rtt@23
double v47; // rt0@24
double v48; // st2@24
double v49; // rtt@24
double v50; // rt0@25
double v51; // st2@25
double v52; // st7@25
double v53; // st2@26
double v54; // st6@26
double v55; // rt2@26
double v56; // st2@26
double v57; // st7@26
double v58; // rtt@28
double v59; // rtt@29
double v60; // rt1@30
double v61; // st2@30
double v62; // st6@30
double v63; // st2@31
double v64; // st7@31
double v65; // rtt@31
double v66; // st2@31
double v67; // st6@31
double v68; // rt0@33
double v69; // st2@33
double v70; // st4@33
double v71; // st5@33
double v72; // st2@33
double v73; // rt0@33
double v74; // st2@33
double v75; // rt1@33
double v76; // st2@33
double v77; // rtt@33
double v78; // rt0@34
double v79; // st2@34
double v80; // rtt@34
double v81; // rt0@35
double v82; // st2@35
double v83; // st7@35
double v84; // st2@36
double v85; // st6@36
double v86; // rt2@36
double v87; // st2@36
double v88; // rtt@38
double v89; // rtt@39
double v90; // st1@40
double v91; // rt1@40
double v92; // st2@40
float *v93; // ecx@42
int v94; // edx@42
double v95; // rt2@43
double v96; // st3@43
double v97; // rt0@43
double v98; // st2@45
double v99; // st7@45
double v100; // rt2@45
double v101; // st2@45
double v102; // st6@45
double v103; // rtt@47
double v104; // st2@47
double v105; // st4@47
double v106; // st5@47
double v107; // st2@47
double v108; // rtt@47
double v109; // st2@47
double v110; // rt0@47
double v111; // st2@47
double v112; // rt2@47
double v113; // rtt@48
double v114; // st2@48
double v115; // rt2@48
double v116; // st1@49
double v117; // rtt@49
double v118; // st2@49
double v119; // st7@49
int v120; // edx@51
int v121; // edi@51
int v122; // ecx@52
unsigned int v123; // edx@52
int v124; // eax@52
int v125; // eax@56
int v126; // edx@56
double v127; // st7@57
int v128; // edx@59
double v129; // st7@59
int v130; // edi@60
int v131; // ecx@60
float v132; // ST18_4@61
double v133; // ST30_8@61
double v134; // st1@61
bool v135; // c0@61
bool v136; // c3@61
double v137; // st1@61
float v138; // ST30_4@63
float v139; // ST30_4@63
float v140; // ST18_4@63
double v141; // ST30_8@63
double v142; // st1@63
bool v143; // c0@63
bool v144; // c3@63
double v145; // st1@63
float v146; // ST30_4@65
float v147; // ST30_4@65
float v148; // ST18_4@65
double v149; // ST30_8@65
double v150; // st1@65
bool v151; // c0@65
bool v152; // c3@65
double v153; // st1@65
float v154; // ST30_4@67
float v155; // ST30_4@67
float v156; // ST18_4@67
double v157; // ST30_8@67
double v158; // st1@67
bool v159; // c0@67
bool v160; // c3@67
double v161; // st1@67
float v162; // ST30_4@69
float v163; // ST30_4@69
int v164; // edi@71
int v165; // ecx@71
int v166; // esi@71
float v167; // ST18_4@72
double v168; // ST30_8@72
double v169; // st1@72
bool v170; // c0@72
bool v171; // c3@72
double v172; // st1@72
float v173; // ST4C_4@74
float v174; // ST4C_4@74
int v175; // edx@75
int v176; // esi@75
int v177; // ecx@76
unsigned int v178; // edx@76
int v179; // eax@76
int v180; // eax@80
int v181; // edx@80
double v182; // st7@81
float EXi; // [sp+10h] [bp-3Ch]@21 MAPDST
float y2; // [sp+14h] [bp-38h]@20 MAPDST
double y2j; // [sp+14h] [bp-38h]@61 MAPDST
int L; // [sp+20h] [bp-2Ch]@5
float *outBuf; // [sp+24h] [bp-28h]@3
float *N; // [sp+28h] [bp-24h]@1
int i; // [sp+2Ch] [bp-20h]@18
int nrLevel; // [sp+38h] [bp-14h]@6 MAPDST
float *G; // [sp+3Ch] [bp-10h]@1
float *xFreq; // [sp+40h] [bp-Ch]@1
int bufLength; // [sp+44h] [bp-8h]@1
int v218; // [sp+48h] [bp-4h]@60

scratch = CG.Scratch;
v3 = Q->G;
xTime = Q->xTime;
v5 = CG.ERB_Length;
++Q->count;
xFreq = scratch;
G = v3;
N = Q->N;
bufLength = v5;
if ( !(Q->Enabled & 0x10000000) )
return -5;
outBuf = signal->buffer;
if ( !signal->buffer )
return -1;
v7 = 0;
L = CG.blockLength;
if ( CG.blockLength >= 4 )
{
nrLevel = (char *)xTime - (char *)scratch;
v8 = &scratch[CG.blockLength];
v9 = xFreq + 1;
v10 = outBuf + 2;
v7 = 0;
do
{
*(v9 - 1) = xTime[v7];
v7 += 4;
v9 += 4;
*v8 = *(v10 - 2);
v8 += 4;
*(v9 - 4) = *(float *)((char *)v9 + nrLevel - 16);
v10 += 4;
*(v8 - 3) = *(float *)((char *)v9 + (char *)outBuf - (char *)xFreq - 16);
*(v9 - 3) = *(float *)((char *)v10 + (char *)xTime - (char *)outBuf - 16);
*(v8 - 2) = *(v10 - 4);
*(v9 - 2) = xTime[v7 - 1];
*(v8 - 1) = *(v10 - 3);
}
while ( v7 < L - 3 );
}
if ( v7 < L )
{
v11 = &xFreq[v7];
v12 = &xFreq[v7 + L];
v13 = L - v7;
do
{
v14 = *(float *)((char *)v11 + (char *)xTime - (char *)xFreq);
++v11;
*(v11 - 1) = v14;
++v12;
--v13;
*(v12 - 1) = *(float *)((char *)v11 + (char *)outBuf - (char *)xFreq - 4);
}
while ( v13 );
}
WindowFft(xFreq, L);
AmpSpectrum(xFreq, xTime);
if ( Q->count < 20 && signal->Silence )
{
if ( v5 > 0 )
{
v15 = 1.0;
v16 = N;
v17 = 0.5;
nrLevel = v5;
while ( 1 )
{
v19 = (float *)((char *)v16 + (char *)xTime - (char *)N);
v20 = v17;
v21 = v15;
v22 = v20;
*(float *)((char *)v19 + (char *)G - (char *)xTime) = v21;
++v16;
v23 = nrLevel-- == 1;
*(v16 - 1) = *v19 * v20 + *(v16 - 1) * v20;
if ( v23 )
break;
v18 = v21;
v17 = v22;
v15 = v18;
}
}
}
else
{
v24 = 0.94999999;
v25 = 0.050000001;
i = 0;
v26 = 0.99800003;
v27 = 0.0020000001;
v28 = 0.99980003;
if ( v5 >= 4 )
{
v29 = (int)(N + 1);
v30 = ((unsigned int)(v5 - 4) >> 2) + 1;
v31 = xTime + 3;
i = 4 * v30;
do
{
y2 = *(v31 - 3);
if ( *(float *)(v29 - 4) <= (double)y2 )
{
if ( Q->count >= 2000 )
{
v47 = y2;
EXi = 0.99980003;
y2 = 0.00019999999;
v48 = v24;
v33 = v47;
v49 = v48;
v35 = v25;
v36 = v49;
}
else
{
v37 = y2;
EXi = v26;
v38 = v27;
v39 = v26;
y2 = v38;
v40 = v38;
v41 = v24;
v33 = v37;
v42 = v41;
v43 = v25;
v36 = v42;
v44 = v43;
v45 = v40;
v26 = v39;
v46 = v45;
v35 = v44;
v27 = v46;
}
}
else
{
v32 = v24;
v33 = y2;
EXi = v32;
v34 = v32;
v35 = v25;
v36 = v34;
y2 = v35;
}
v50 = v35;
v51 = v33 * y2 + *(float *)(v29 - 4) * EXi;
v52 = v50;
*(float *)(v29 - 4) = v51;
y2 = *(float *)(v29 + (char *)xTime - (char *)N);
if ( *(float *)v29 <= (double)y2 )
{
if ( Q->count >= 2000 )
{
v59 = y2;
EXi = 0.99980003;
y2 = 0.00019999999;
v56 = v52;
v57 = v36;
v54 = v59;
}
else
{
v58 = y2;
EXi = v26;
y2 = v27;
v56 = v52;
v57 = v36;
v54 = v58;
}
}
else
{
v53 = v36;
v54 = y2;
EXi = v53;
v55 = v53;
v56 = v52;
v57 = v55;
y2 = v56;
}
v60 = v56;
v61 = v54 * y2 + *(float *)v29 * EXi;
v62 = v60;
*(float *)v29 = v61;
y2 = *(v31 - 1);
if ( *(float *)(v29 + 4) <= (double)y2 )
{
if ( Q->count >= 2000 )
{
v78 = y2;
EXi = 0.99980003;
y2 = 0.00019999999;
v79 = v57;
v64 = v78;
v80 = v79;
v66 = v62;
v67 = v80;
}
else
{
v68 = y2;
EXi = v26;
v69 = v27;
v70 = v26;
y2 = v69;
v71 = v69;
v72 = v57;
v64 = v68;
v73 = v72;
v74 = v62;
v67 = v73;
v75 = v74;
v76 = v71;
v26 = v70;
v77 = v76;
v66 = v75;
v27 = v77;
}
}
else
{
v63 = v57;
v64 = y2;
EXi = v63;
v65 = v63;
v66 = v62;
v67 = v65;
y2 = v66;
}
v81 = v66;
v82 = v64 * y2 + EXi * *(float *)(v29 + 4);
v83 = v81;
*(float *)(v29 + 4) = v82;
y2 = *v31;
if ( *(float *)(v29 + 8) <= (double)y2 )
{
if ( Q->count >= 2000 )
{
v89 = y2;
EXi = 0.99980003;
y2 = 0.00019999999;
v87 = v83;
v24 = v67;
v85 = v89;
}
else
{
v88 = y2;
EXi = v26;
y2 = v27;
v87 = v83;
v24 = v67;
v85 = v88;
}
}
else
{
v84 = v67;
v85 = y2;
EXi = v84;
v86 = v84;
v87 = v83;
v24 = v86;
y2 = v87;
}
v90 = *(float *)(v29 + 8);
v29 += 16;
v31 += 4;
--v30;
v91 = v87;
v92 = v85 * y2 + v90 * EXi;
v25 = v91;
*(float *)(v29 - 8) = v92;
}
while ( v30 );
}
if ( i < v5 )
{
v93 = &N[i];
v94 = v5 - i;
while ( 1 )
{
y2 = *(float *)((char *)v93 + (char *)xTime - (char *)N);
if ( *v93 <= (double)y2 )
{
if ( Q->count >= 2000 )
{
v113 = y2;
EXi = v28;
y2 = 0.00019999999;
v114 = v24;
v99 = v113;
v115 = v114;
v101 = v25;
v102 = v115;
}
else
{
v103 = y2;
EXi = v26;
v104 = v27;
v105 = v26;
y2 = v104;
v106 = v104;
v107 = v24;
v99 = v103;
v108 = v107;
v109 = v25;
v102 = v108;
v110 = v109;
v111 = v106;
v26 = v105;
v112 = v111;
v101 = v110;
v27 = v112;
}
}
else
{
v98 = v24;
v99 = y2;
EXi = v98;
v100 = v98;
v101 = v25;
v102 = v100;
y2 = v101;
}
v116 = *v93;
++v93;
--v94;
v117 = v101;
v118 = v99 * y2 + v116 * EXi;
v119 = v117;
*(v93 - 1) = v118;
if ( !v94 )
break;
v95 = v28;
v96 = v119;
v24 = v102;
v97 = v96;
v28 = v95;
v25 = v97;
}
}
}
if ( Q->Enabled & 0x2000000 )
{
v128 = 0;
v129 = CG.dbTable[Q->nrLeveldB];
if ( v5 >= 4 )
{
v130 = (int)(N + 2);
v218 = (char *)N - (char *)G;
v131 = (int)(G + 1);
nrLevel = (char *)xTime - (char *)N;
do
{
EXi = xTime[v128];
v132 = *(float *)(v130 - 8) * 8.0;
v133 = EXi - v132;
v134 = EXi * v129;
y2j = v134;
v135 = v133 < v134;
v136 = v133 == v134;
v137 = v133;
if ( v135 || v136 )
v137 = y2j;
v138 = v137;
v139 = v138 / (EXi + 1.0 + 2.0);
*(float *)(v131 - 4) = v139 * 0.300000011920929 + *(float *)(v131 - 4) * 0.699999988079071;
EXi = *(float *)(nrLevel + v131 + v218);
v140 = *(float *)(v131 + v218) * 8.0;
v141 = EXi - v140;
v142 = EXi * v129;
y2j = v142;
v143 = v141 < v142;
v144 = v141 == v142;
v145 = v141;
if ( v143 || v144 )
v145 = y2j;
v146 = v145;
v147 = v146 / (EXi + 1.0 + 2.0);
*(float *)v131 = v147 * 0.300000011920929 + *(float *)v131 * 0.699999988079071;
EXi = *(float *)(v130 + nrLevel);
v148 = *(float *)v130 * 8.0;
v149 = EXi - v148;
v150 = EXi * v129;
y2j = v150;
v151 = v149 < v150;
v152 = v149 == v150;
v153 = v149;
if ( v151 || v152 )
v153 = y2j;
v154 = v153;
v155 = v154 / (EXi + 1.0 + 2.0);
*(float *)(v131 + 4) = v155 * 0.300000011920929 + *(float *)(v131 + 4) * 0.699999988079071;
EXi = xTime[v128 + 3];
v156 = *(float *)(v130 + 4) * 8.0;
v157 = EXi - v156;
v158 = EXi * v129;
y2j = v158;
v159 = v157 < v158;
v160 = v157 == v158;
v161 = v157;
if ( v159 || v160 )
v161 = y2j;
v162 = v161;
v5 = bufLength;
v128 += 4;
v131 += 16;
v130 += 16;
v163 = v162 / (EXi + 1.0 + 2.0);
*(float *)(v131 - 8) = v163 * 0.300000011920929 + *(float *)(v131 - 8) * 0.699999988079071;
}
while ( v128 < bufLength - 3 );
}
if ( v128 < v5 )
{
v164 = (char *)N - (char *)G;
v165 = (int)&G[v128];
v166 = v5 - v128;
do
{
EXi = *(float *)(v165 + v164 + (char *)xTime - (char *)N);
v167 = *(float *)(v165 + v164) * 8.0;
v168 = EXi - v167;
v169 = EXi * v129;
y2j = v169;
v170 = v168 < v169;
v171 = v168 == v169;
v172 = v168;
if ( v170 || v171 )
v172 = y2j;
v173 = v172;
v165 += 4;
--v166;
v174 = v173 / (EXi + 1.0 + 2.0);
*(float *)(v165 - 4) = v174 * 0.300000011920929 + *(float *)(v165 - 4) * 0.699999988079071;
}
while ( v166 );
}
FreqSmooth(G, xFreq, 0.5);
v175 = L;
v176 = 0;
if ( L >= 4 )
{
v177 = (int)(outBuf + 3);
v178 = ((unsigned int)(L - 4) >> 2) + 1;
v179 = (int)(xTime + 1);
v176 = 4 * v178;
do
{
v179 += 16;
*(float *)(v179 - 20) = *(float *)(v177 - 12);
v177 += 16;
--v178;
*(float *)(v179 - 16) = *(float *)(v179 + (char *)outBuf - (char *)xTime - 16);
*(float *)(v179 - 12) = *(float *)(v177 - 20);
*(float *)(v179 - 8) = *(float *)(v177 - 16);
}
while ( v178 );
v175 = L;
}
if ( v176 < v175 )
{
v180 = (int)&xTime[v176];
v181 = v175 - v176;
do
{
v182 = *(float *)((char *)outBuf - (char *)xTime + v180);
v180 += 4;
--v181;
*(float *)(v180 - 4) = v182;
}
while ( v181 );
}
Reconstruct(xFreq, outBuf, Q->by);
return 0;
}
v120 = L;
v121 = 0;
if ( L >= 4 )
{
v122 = (int)(outBuf + 3);
v123 = ((unsigned int)(L - 4) >> 2) + 1;
v124 = (int)(xTime + 1);
v121 = 4 * v123;
do
{
v124 += 16;
*(float *)(v124 - 20) = *(float *)(v122 - 12);
v122 += 16;
--v123;
*(float *)(v124 - 16) = *(float *)((char *)outBuf - (char *)xTime + v124 - 16);
*(float *)(v124 - 12) = *(float *)(v122 - 20);
*(float *)(v124 - 8) = *(float *)(v122 - 16);
}
while ( v123 );
v120 = L;
}
if ( v121 >= v120 )
return 0;
v125 = (int)&xTime[v121];
v126 = v120 - v121;
do
{
v127 = *(float *)(v125 + (char *)outBuf - (char *)xTime);
v125 += 4;
--v126;
*(float *)(v125 - 4) = v127;
}
while ( v126 );
return 0;
}
``````

These casts are done to make the pointer arithmetic that's happening more clear.

When you add an integer to a pointer, the integer internally gets multiplied by the size of the object the pointer is pointing to, so when `fp` is a float pointer, assuming 4 byte floats, `fp+1` will point to a memory location 4 bytes behind `fp`. And in the same way, pointer subtraction divides the byte difference by the object type, so with `fp1` and `fp2` being float pointers, something like

``````fp1=&array[3];
fp2=&array[7];
printf("%d\n", fp2-fp1);
``````

you'll get a result of 4, not 16, even though there are 16 bytes between both addresses. (Which is the reason why pointer subtraction works with the same pointer type only, and is undefined behaviour if both pointers don't point into the same array).

Now look at an expression like

``````*(float *)((char *)v9 + (char *)outBuf - (char *)xFreq - 16);
``````

With `v9`, `outBuf`, and `xFreq` declared `float *`, this is identical to

``````*(v9 + outBuf - xFreq - 4)
``````

or even

``````v9[outBuf-xFreq-4].
``````

But, as ida can only guess the data types, there is a certain chance it guesses wrong, and you might want to change them later. But if you do that, the meaning of the expression changes as well, as the integer part of the expression gets scaled differently. To avoid that, when working with pointer arithmetic, ida casts all pointers to `char *` first, does its arithmetic, then casts the result back to what the pointer is supposed to be pointing to.

This also helps you match the assembler with the original source, because it avoids turning a `sub XXX, 16` assembly instruction into a `XXX - 4` C expression.

• I have pdb file of above program still ida don't use the name of local variable in case you want to have ida data base let me know .thanx Guntram Blohm for your explanation – Arun Apr 19 '16 at 14:10