Casting a memory address into a pointer type to get the value at address.

Why does the following code produce different results for Method 1 and Method 2?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/* 
 * File:   main.cpp
 * Author: cmisip
 *
 * Created on July 19, 2017, 4:50 PM
 */

#include <cstdlib>
#include <cstring>
#include <stdint.h>
#include <iostream>

using namespace std;

/*
 * 
 */

struct mmal_motion_vector {
     char x_vector;
     char y_vector; 
     short sad;
    };
    
int main(int argc, char** argv) {
    
   
    
    uint16_t size=20;
    uint16_t mv_size=20*4+4;
    
    
    std::cout << "MV SIZE " << mv_size << std::endl;
    std::cout << "ARRAY SIZE " << mv_size/sizeof(mmal_motion_vector) -1 << std::endl;
    
    uint8_t * mvect_buffer=(uint8_t*)malloc(mv_size);
    
    struct mmal_motion_vector mvarray[size];
    
    //Fill array with values
    for (int i=0;i < size ; i++) {
        mvarray[i].x_vector=5;
        mvarray[i].y_vector=10;
        mvarray[i].sad = 7;
        std::cout << "COUNTS " << i <<  " " << (int)mvarray[i].x_vector << (int)mvarray[i].y_vector << std::endl;
    }
    
    
    //////////////////////WRITE                
    uint8_t offset = 4;  //Start at 4th byte, since we will save size and vec_type in first 4 bytes    
    const mmal_motion_vector *mvs = (const mmal_motion_vector *)mvarray;
                        
                        for (int i=0;i < size ; i++) {
                            const mmal_motion_vector *mv = &mvs[i]; 
                            mmal_motion_vector *wv;
                           
                             wv->x_vector = mv->x_vector;
                             wv->y_vector = mv->y_vector;
                             std::cout << "COUNTW " <<  i << " x_vector " << (int)wv->x_vector << " Y_vector " << (int)wv->y_vector << std::endl;  //Values displayed
                             memcpy(mvect_buffer+offset, wv, sizeof(mmal_motion_vector));
                          
                             offset+=sizeof(mmal_motion_vector);
                             
                            
                            
                        } 
    
    uint16_t vec_type = 69;
    
    //Save the size and vec_type
    memcpy(mvect_buffer,&size,2);
    memcpy(mvect_buffer+2,&vec_type,2);
              
    
    /////////////////READ
    
    //Method 1, use pointer casts
    const uint16_t *rsize;
    const uint16_t *vtype;
    
    rsize=(uint16_t * )mvect_buffer;  //works
    vtype=(uint16_t * )mvect_buffer+2; //wrong
    
    //Method 2, save into variables
    uint16_t rsize2;
    uint16_t vtype2;
    memcpy(&rsize2, mvect_buffer,2);
    memcpy(&vtype2, mvect_buffer+2,2);
    
    
    const mmal_motion_vector *mvo = (const mmal_motion_vector *)mvect_buffer+4; //wrong SHORT 3 values
     for (int i=0;i < size ; i++) {
         const mmal_motion_vector *mv = &mvo[i];
         
         
         std::cout << "COUNTR " <<  i << " x_vector " << (int)mv->x_vector << " Y_vector " << (int)mv->y_vector << std::endl;   
     }
    
    std::cout << "SIZE " << *rsize << " size " << sizeof (*rsize) << std::endl;
    std::cout << "VECTS " << *vtype << " size " << sizeof (*vtype) << std::endl;  //WRONG VALUE returned
    
    std::cout << "SIZE " << rsize2 << " size "  << sizeof(rsize2) << std::endl;
    std::cout << "VECTS " << vtype2 << " size " << sizeof(vtype2) <<  std::endl;
                        
                        
    free(mvect_buffer);                    

    return 0;
}



Result :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
MV SIZE 84
ARRAY SIZE 20
COUNTS 0  510
COUNTS 1  510
COUNTS 2  510
COUNTS 3  510
COUNTS 4  510
COUNTS 5  510
COUNTS 6  510
COUNTS 7  510
COUNTS 8  510
COUNTS 9  510
COUNTS 10  510
COUNTS 11  510
COUNTS 12  510
COUNTS 13  510
COUNTS 14  510
COUNTS 15  510
COUNTS 16  510
COUNTS 17  510
COUNTS 18  510
COUNTS 19  510
COUNTW 0 x_vector 5 Y_vector 10
COUNTW 1 x_vector 5 Y_vector 10
COUNTW 2 x_vector 5 Y_vector 10
COUNTW 3 x_vector 5 Y_vector 10
COUNTW 4 x_vector 5 Y_vector 10
COUNTW 5 x_vector 5 Y_vector 10
COUNTW 6 x_vector 5 Y_vector 10
COUNTW 7 x_vector 5 Y_vector 10
COUNTW 8 x_vector 5 Y_vector 10
COUNTW 9 x_vector 5 Y_vector 10
COUNTW 10 x_vector 5 Y_vector 10
COUNTW 11 x_vector 5 Y_vector 10
COUNTW 12 x_vector 5 Y_vector 10
COUNTW 13 x_vector 5 Y_vector 10
COUNTW 14 x_vector 5 Y_vector 10
COUNTW 15 x_vector 5 Y_vector 10
COUNTW 16 x_vector 5 Y_vector 10
COUNTW 17 x_vector 5 Y_vector 10
COUNTW 18 x_vector 5 Y_vector 10
COUNTW 19 x_vector 5 Y_vector 10
COUNTR 0 x_vector 5 Y_vector 10
COUNTR 1 x_vector 5 Y_vector 10
COUNTR 2 x_vector 5 Y_vector 10
COUNTR 3 x_vector 5 Y_vector 10
COUNTR 4 x_vector 5 Y_vector 10
COUNTR 5 x_vector 5 Y_vector 10
COUNTR 6 x_vector 5 Y_vector 10
COUNTR 7 x_vector 5 Y_vector 10
COUNTR 8 x_vector 5 Y_vector 10
COUNTR 9 x_vector 5 Y_vector 10
COUNTR 10 x_vector 5 Y_vector 10
COUNTR 11 x_vector 5 Y_vector 10
COUNTR 12 x_vector 5 Y_vector 10
COUNTR 13 x_vector 5 Y_vector 10
COUNTR 14 x_vector 5 Y_vector 10
COUNTR 15 x_vector 5 Y_vector 10
COUNTR 16 x_vector 5 Y_vector 10
COUNTR 17 x_vector 0 Y_vector 0
COUNTR 18 x_vector -127 Y_vector -1
COUNTR 19 x_vector 0 Y_vector 0
SIZE 20 size 2
VECTS 2565 size 2
SIZE 20 size 2
VECTS 69 size 2


Is it not possible to get values from memory address using Method 1?

Thanks,
Chris
Last edited on
1
2
3
4
//line 61
mmal_motion_vector *wv; //uninitialized
wv->x_vector = mv->x_vector; //dereferencing an invalid pointer
wv->y_vector = mv->y_vector;


1
2
3
vtype=(uint16_t * )mvect_buffer+2; //wrong
vtype = ((uint16_t*) mvect_buffer ) + 2; //equivalent, first cast then advance
vtype = (uint16_t*) (mvect_buffer+2); //first advance, then cast 
review pointer arithmetic. (same problem on line 97 «short 3 values»)


Also, line 57 does not need to cast and makes it confusing.
const mmal_motion_vector *mvs = mvarray;

¿And what's the point of the loop 59--72?
memcpy(mvect_buffer+offset, mvarray, sizeof(mvarray));
Last edited on
Thanks, that takes care of the problem. I chose to advance, then cast.


vtype=(uint16_t * )mvect_buffer+2; //wrong
vtype = ((uint16_t*) mvect_buffer ) + 2; //equivalent, first cast then advance
vtype = (uint16_t*) (mvect_buffer+2); //first advance, then cast


1
2
3
4
//line 61
mmal_motion_vector *wv; //uninitialized
wv->x_vector = mv->x_vector; //dereferencing an invalid pointer
wv->y_vector = mv->y_vector;


Why does the above get the job done? I want wv to have the same values as mv. Isn't wv a stack allocated pointer here? The memcpy operation shows that the values are indeed copied onto wv which are then copied into mvect_buffer.


Also, line 57 does not need to cast and makes it confusing.
const mmal_motion_vector *mvs = mvarray;


Yes, the cast is not needed, but where I am putting this code, mvarray is not actually an array of mmal_motion_vector but a sequence of bytes of uint8_t. So the cast in that case would be necessary, right?


¿And what's the point of the loop 59--72?
memcpy(mvect_buffer+offset, mvarray, sizeof(mvarray));


I am simulating write to a uint8_t * buffer, where a different struct object is written into mvect_buffer. wv should have been a pointer to struct motion_vector. Values from mv will be copied onto wv and wv is saved in the mvect_buffer. The code I posted was wrong. It should have been.

memcpy(mvect_buffer+offset, wv, sizeof(mmal_motion_vector))

I have edited the post multiple times and got your reply in between edits.

Is there anything concerning with the code?

Thanks,
Chris



> Why does the above get the job done? I want wv to have the same values as
> mv. Isn't wv a stack allocated pointer here?
undefined behaviour.
¿where is `wv' pointing to?

there is no need to use a pointer
1
2
mmal_motion_vector wv = mvs[i];
memcpy(mvect_buffer+offset, &wv, sizeof(wv));

The point of the test code is to track down alignment errors in my actual project code.

I am trying to run the program in the raspberry pi.

According to this:

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka3934.html

I need to make sure memcpy calls are with properly aligned buffers.

Here is info on the actual structs:

1
2
3
4
5
6
7
8
9
10
struct mmal_motion_vector {
     char x_vector;
     char y_vector; 
     short sad;
};

struct motion_vector { //SW vectors will be 4x4, HW vectors will be 16x16
    uint16_t xcoord;  //location of top left corner
    uint16_t ycoord;
};



The actual project code snippet of the work so far is

WRITE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
if(buffer->flags & MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO) {
                          
                        uint8_t offset=sizeof(uint16_t)*2; //skip the first 4 bytes, reserved for size and vec_type
                        uint16_t vector_ceiling=(((mRawFrame->width * mRawFrame->height)/256)*(double)20)/100;  //FIXMEC, the size of hardware buffer is smaller than software buffer so can save memory by requesting smaller buffer size
                        uint16_t vec_count=0;  
                        
                        mmal_buffer_header_mem_lock(buffer);
                        uint16_t size=buffer->length/sizeof(mmal_motion_vector);
                        
                        const mmal_motion_vector *mvi = (const mmal_motion_vector *)buffer->data;  //FIXMEC, would it be faster to memcpy to a temporary buffer so we dont hold up the hardware buffer as the encoder is not synchronous
                        
                        for (int i=0;i < size ; i++) {
                            motion_vector mvt;
                            const mmal_motion_vector *mv = &mvi[i]; 
                            
                            if ((abs(mv->x_vector) + abs(mv->y_vector)) < 1)
                               continue;
                          
                            mvt.xcoord = (i*16) % (mVideoCodecContext->width + 16);
                            mvt.ycoord = ((i*16)/(mVideoCodecContext->width+16))*16;
                            
                            //Future expansion, save the magnitude of vectors
                            //mvt.x_vector = mv->x_vector;
                            //mvt.y_vector = mv->y_vector;
                            vec_count++;
                            
                            memcpy((motion_vector *)mvect_buffer+offset,&mvt,sizeof(motion_vector));
                            offset+=sizeof(motion_vector);
                            
                            if (vec_count > vector_ceiling) {  
                              char * temp_ptr = (char *)mvect_buffer;
                              memset(temp_ptr,0,image.mv_size);
                              vec_count=0;
                            break;
                        }    
                            
                         mmal_buffer_header_mem_unlock(buffer);    
                            
                         } 
                         memcpy((uint16_t *)mvect_buffer,&vec_count, sizeof(vec_count));  //size at first byte
                         uint16_t vec_type = 0;
                         
                         memcpy((uint16_t *)mvect_buffer+sizeof(vec_count),&vec_type, sizeof(vec_type));   //type of vector at 3rd byte
                         
                         //Info("FFMPEG HW VEC_COUNT %d, ceiling %d", vec_count, vector_ceiling);
                        
                      } 


READ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
if (mvect_buffer) {
        //first 16bit value is size
        size=(uint16_t * )mvect_buffer;
        //second 16 bit value is source type of macroblock : 0 hardware, 1 software.  //FIXME, could be 8 bit value but probably better to keep things even
        vec_type=(uint16_t * )(mvect_buffer+sizeof(*size));  
    
        //sizeof would be safer in the long run if we decide to make changes to these types
        const motion_vector *mvo = (const motion_vector *)(mvect_buffer+sizeof(*size)+sizeof(*vec_type));
        
        for (int i = 0; i < *size; i++) {
                const motion_vector *mv = &mvo[i];
                 
                //Are the vectors inside the zone polygon?
                if (!polygon.isInside(Coord(mv->xcoord,mv->ycoord)))      
                    continue;
                
                    uint16_t x;
                    uint16_t y;
                        
                if (*vec_type == 0 )  //hardware macroblock with size of 16x16, there are 16 4x4 blocks in each one
                  for (uint16_t i=0 ; i< 4; i++) {
                           for (uint16_t j=0 ; j< 4; j++) {
                                x=mv->xcoord+i*4;
                                y=mv->ycoord+j*4;
                                x_sum+=x;
                                y_sum+=y;   
                                vec_count++;
                           }
                  }
                else //software macroblock with size of 4x4
                  vec_count++;  
             
                     
                       
        }
    }   


Can you see any problems?

Thanks,
Chris
line 27: memcpy((motion_vector *)mvect_buffer+offset,&mvt,sizeof(motion_vector));
that casting is wrong, there should be no casting.
line 43 seems to have the same problem, but I did not analyse it.
when working with offsets, mantain the pointer as a char* and the offset as a byte count.
if you need to work with jumps of other size, you may use array notation.
Forgot the first lesson, if using pointer arithmetic with a cast, need parenthesis around the arithmetic.

I am trying to understand pointer alignment concept as that is where my code seems to be causing alignment traps to be triggered.

From the link above for arm memcpy:

1
2
3
4
5
6
7
8
9
10
11
12
#include <string.h>

unsigned int * const dest;

void example (unsigned int * const unaligned_ptr)
{
  __packed unsigned int * packed_ptr = unaligned_ptr;
  char * temp_ptr = (char *)unaligned_ptr;
  memcpy(dest, unaligned_ptr, 32);         /* Unsafe */
  memcpy(dest, (void *)packed_ptr, 32);    /* Safe   */
  memcpy(dest, temp_ptr, 32);              /* Safe   */
}


The temp_ptr pointer was necessary to force byte by byte memcpy type. Since the code I am writing needs to be written for the arm architecture which I have read performs better with 4 byte memcpy transfers, I am trying to tell the arm compiler to select the 4 byte memcpy by casting the dest pointer to motion_vector *. The source pointer is the address of a 4 byte motion_vector object so the compiler knows that it is 4 bytes in size. However mvect_buffer is declared as a uint8_t pointer and I felt that I needed to cast to tell the compiler to select the 4 byte memcpy version? Is that the way to do it? Leaving the cast to motion_vector* inside memcpy call seems to have no ill effects on X86. In the above example, the dest is an int * while the source was a char *. Is it enough to just make sure the source pointer is 4 bytes to allow compiler to select the 4 byte memcpy version?

I am really convinced that the alignment traps are triggered by memcpy, but I realize the mistake with the pointer arithmetic not having parenthesis now. If the cast happened before the arithmetic, where I thought I was jumping forward 4 bytes (offset of 4), I actually was jumping forward 4 motion_vector objects (16 bytes). Maybe that was the issue.


memcpy((motion_vector*)(mvect_buffer+offset), &wv, sizeof(motion_vector));

Thanks,
Chris


Last edited on
memcpy should not need casting, it should use the best approach for your machine automatically.

it may be in your best interest to have a multiple of 4 for your data structure, which you can force in a variety of ways.
Last edited on
These are the dmesg errors I am getting.

1
2
3
4
5
6
7
8
Alignment trap: not handling instruction e1992f9f at [<74d4f968>]
[  665.645531] Unhandled fault: alignment exception (0x001) at 0x0002a19e
[  665.647258] pgd = aa518000
[  665.648851] [0002a19e] *pgd=2a4a1835, *pte=1e13b59f, *ppte=1e13be7e
[  744.639854] Alignment trap: not handling instruction e1992f9f at [<74dbd968>]
[  744.639865] Unhandled fault: alignment exception (0x001) at 0x26110a26
[  744.641720] pgd = aa288000
[  744.643341] [26110a26] *pgd=00000000


Do you think its at all related to the code I posted?

Thanks,
Chris
I just read an article about this.

http://antirez.com/news/111

He recommends to change pointer dereference to memcpy to avoid the alignment issue. I changed the test code to reflect this. I hope these changes are correct.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/* 
 * File:   main.cpp
 * Author: cmisip
 *
 * Created on July 22, 2017, 7:10 PM
 */

#include <cstdlib>
#include <cstring>
#include <stdint.h>
#include <iostream>

using namespace std;

/*
 * 
 */

struct mmal_motion_vector {
     char x_vector;
     char y_vector; 
     short sad;
    };
    
struct motion_vector{
uint16_t x_mag;
uint16_t y_mag;
};
    
int main(int argc, char** argv) {
    
   
    
    uint16_t size=20;
    uint16_t mv_size=20*4+4;
    
    
    std::cout << "MV SIZE " << mv_size << std::endl;
    std::cout << "ARRAY SIZE " << mv_size/sizeof(mmal_motion_vector) -1 << std::endl;
    
   
    
    
    //1. Artificially construct the source of the data
    struct mmal_motion_vector mvarray[size];
    
    //Fill array with values
    for (int i=0;i < size ; i++) {
        mvarray[i].x_vector=(char)i;
        mvarray[i].y_vector=(char)(10+i);
        mvarray[i].sad = 7;
        std::cout << "COUNTS " << i << " x_vector " << (int)mvarray[i].x_vector << " y_vector " << (int)mvarray[i].y_vector  << std::endl;
    }
    
    //2. Package the source of data in a uint8_t buffer since that is what project code is using to pass data around.
     uint8_t * mvsource=(uint8_t *)mvarray;  //This cast just simulates that the source pointer is uint8_t * buffer 
    
    
    //3. WRITE to mvect_buffer    
     
    uint8_t * mvect_buffer=(uint8_t*)malloc(mv_size); 
    
    uint8_t s_offset = 0; //Start reading source address at byte 0    
    uint8_t t_offset = 4; //Start writing target at 4th byte, since we will save size and vec_type in first 4 bytes 
    
   
                        
                        memset(mvect_buffer,0,mv_size);
                        for (int i=0;i < size ; i++) {
                             mmal_motion_vector mv;
                             memcpy(&mv,mvsource+s_offset,sizeof(mmal_motion_vector));
                       
                             motion_vector wv;
                           
                             wv.x_mag = mv.x_vector;
                             wv.y_mag = mv.y_vector;
                             
                             std::cout << "COUNTW " <<  i << " x_vector " << (int)wv.x_mag << " Y_vector " << (int)wv.y_mag << std::endl;  //Values displayed
                             memcpy(mvect_buffer+t_offset, &wv, sizeof(motion_vector));
                          
                             s_offset+=sizeof(mmal_motion_vector);
                             t_offset+=sizeof(motion_vector);
                            
                        } 
    
    uint16_t vec_type = 69;
    
    //Save the size and vec_type
    memcpy(mvect_buffer,&size,2);
    memcpy(mvect_buffer+2,&vec_type,2);
              
    
    //4.READ
    
    uint16_t rsize2;
    uint16_t vtype2;
    memcpy(&rsize2, mvect_buffer,2);
    memcpy(&vtype2, mvect_buffer+2,2);
    
    uint8_t offset=4; //Start reading vector data at address 4
    for (int i=0;i < size ; i++) {
         motion_vector mv;
         memcpy(&mv,mvect_buffer+offset,sizeof(mv));         
         offset+=sizeof(motion_vector);
         
         std::cout << "COUNTR " <<  i << " x_vector " << (int)mv.x_mag << " Y_vector " << (int)mv.y_mag << std::endl;   
     }
    
    
    std::cout << "SIZE " << rsize2 << " size "  << sizeof(rsize2) << std::endl;
    std::cout << "VECTS " << vtype2 << " size " << sizeof(vtype2) <<  std::endl;
                        
                        
    free(mvect_buffer);                    

    return 0;
}





Do you think the above code would be alignment proof?

Thanks,
Chris
Topic archived. No new replies allowed.