understanding pointer to an image in memory

Discussion in 'C++' started by Trepx, Oct 4, 2008.

  1. Trepx

    Trepx New Member

    Joined:
    Oct 4, 2008
    Messages:
    2
    Likes Received:
    0
    Trophy Points:
    0
    Hello,

    I'm trying to understand how to access data from a pointer in memory. I have some code which is used for manipulating the data of an image. The code uses a uint8* pointer to reference the memory address of the image. The code has this as example of manipulating the image's data:

    Code:
    		
    for ( long imageSize = WIDTH * HEIGHT; imageSize > 0; --imageSize) 		{ 			
        *(data++) = (uint8) fillValue; 		
    }
    can someone explain what's is going on? i.e. what is the ++ operator doing?

    How would I go about reading the data in this image. For example if I knew it was an integer image?

    Thanks for any pointers (sorry)
     
  2. xpi0t0s

    xpi0t0s Mentor

    Joined:
    Aug 6, 2004
    Messages:
    3,009
    Likes Received:
    203
    Trophy Points:
    63
    Occupation:
    Senior Support Engineer
    Location:
    England
    It's looping from data to data+WIDTH*HEIGHT filling the memory with fillValue. I'd guess this is optimised code, because the loop runs backwards, i.e. from n to 0, which is arguably more efficient than looping from 0 to n, and they're not just using memset(). I'd also guess it was unnecessarily optimised, based on what the programmer thought would run slowly rather than based on hard data from a profiler.
     
  3. Trepx

    Trepx New Member

    Joined:
    Oct 4, 2008
    Messages:
    2
    Likes Received:
    0
    Trophy Points:
    0
    Hi xpi0t0s,

    Thanks for the reply. You say
    . Does that mean the code could be written as
    Code:
    for ( long imageSize = WIDTH * HEIGHT; imageSize > 0; --imageSize) 		{ 			
        *(data[imageSize]) = (uint8) fillValue; 		
    }
    and it would do the same thing? I'm still a little uncomfortable on what the ++ operator does as I thought it incremented the value of a variable by 1.

    Also would you be able to explain how I would go about getting the pixel intensity values out of the pointer? or would this require more knowledge of the image's data format?

    Thank
    T
     
  4. xpi0t0s

    xpi0t0s Mentor

    Joined:
    Aug 6, 2004
    Messages:
    3,009
    Likes Received:
    203
    Trophy Points:
    63
    Occupation:
    Senior Support Engineer
    Location:
    England
    No. Suppose WIDTH*HEIGHT=10. Then data[imageSize] = data+10, which is one byte too far on. Congratulations on finding out how easy it is to do a buffer overrun and corrupt application memory! In the original code the final value of data would be data+imageSize because of the post-increment, but nothing would have been written to that memory location. Let's dry run that to WIDTH*HEIGHT=3 so you can see what's going on:

    Enter the for loop, let's say data=1000. imageSize=3.
    *(data++)=fillValue; // Post-increment data, which means data++ evaluates to 1000 but data now contains 1001. Copy fillValue to 1000.
    Decrement imageSize. Must be pre-decrement, which means that the value of --imageSize is what imageSize contains AFTER the decrement (contrast with post-increment). So imageSize=2, which taken as boolean is TRUE, so loop.
    *(data++)=fillValue; // data++ = 1001; data contains 1002. Copy fillValue to 1001.
    Decrement imageSize. imageSize=1, which taken as boolean is TRUE, so loop.
    *(data++)=fillValue; // data++ = 1002; data contains 1003. Copy fillValue to 1002.
    Decrement imageSize. imageSize=0, which taken as boolean is FALSE, so the loop ends.
    So as you can see data now contains 1003, but the last memory location written to was 1002.

    Yes, ++ increments by one, but watch out: it increments pointers by one of what it's pointing to. Which makes sense; if you have struct s { lots of stuff } *p; p=malloc(10*sizeof(struct s)); then you would want p++ to point to the NEXT struct s, not to memory location (void*)(p)+1. So if p=1000 and sizeof(struct s) is 20 then p++=1020, not 1001.

    Without further information on the image format in question there's no way I can answer the question about pixel intensity values. All the loop above does is to block fill the entire image data with the same numeric value, which is likely a fairly useless example, and I'd say it's going a bit far to call it an "example of manipulating the image's data". A proper example might be to change all red pixels in a particular area to blue; it would give you some idea of what constitutes a red pixel, how to determine where a pixel at a particular x,y coordinate is in memory, and how to set that pixel to blue.
     
  5. xpi0t0s

    xpi0t0s Mentor

    Joined:
    Aug 6, 2004
    Messages:
    3,009
    Likes Received:
    203
    Trophy Points:
    63
    Occupation:
    Senior Support Engineer
    Location:
    England
    You're right to be uncomfortable about ++. Get everything else sorted first. Use x++; as a statement in its own right as a shorthand version of x=x+1; Once you've sorted everything else out in your mind, then you can start moving x++ into expressions. DO NOT use the same variable more than once in the same expression if you're using side effects; even something as simple as printf("%d %d",x,x++); is undefined (i.e. different compilers will handle it differently and any code written in such a way will not be portable). So one compiler might treat that as printf x,x+1; x+=1; another as printf x+1,x; x+=1; (order of evaluation reversed); another as printf x,x; x+=1;

    x++ means take the value of x, and some time later (when precisely is undefined) increment x.

    Feel free to experiment with all sorts of weird stuff like int y=x++ + ++x; but remember: what happens in the compiler you're using is not definitive; it's not "the only correct way of interpreting the code".
     
  6. oogabooga

    oogabooga New Member

    Joined:
    Jan 9, 2008
    Messages:
    115
    Likes Received:
    11
    Trophy Points:
    0
    The increment is done immediately after the value is used, which is a fairly precise definition of "when". It is the order of evaluation of arguments to a function that was left implementation dependent, although I do not believe that you would ever get "printf x,x+1;x+=1" (from your example).
    Code:
        int x = 1;
        // Could be 1, 1 or 2, 1 depending on order of evaluation of args.
        printf( "%d, %d\n", x, x++);
    
        x = 1;
        // Guaranteed 1, 1 (order of evaluation defined)
        cout << x << ", " << x++ << endl;
     
  7. xpi0t0s

    xpi0t0s Mentor

    Joined:
    Aug 6, 2004
    Messages:
    3,009
    Likes Received:
    203
    Trophy Points:
    63
    Occupation:
    Senior Support Engineer
    Location:
    England
    It's not defined as "immediately after". That's the problem; it's not _precisely_ defined. If x=1, what's y=x++ + x++? 1+2, if immediately after. But VS2005 if presented with
    Code:
    	int x=1;
    	int y=x++ + x++;
    	printf("%d %d %d\n",y,x++,x++);
    	cout << x << ':' << x++ << endl;
    
    displays
    2 4 3
    6:5
    Have to say I didn't expect 6:5 for the cout line. The order of _execution_ is guaranteed [starts with op <<(cout,x), ends with op <<(ostream,endl)], but the order of _evaluation_ isn't.

    Here's another good one:
    Code:
    	int x=5, y=100;
    	int z=x++ + x++ + y++;
    	printf("%d\n",z);
    	x=5; y=100;
    	printf("%d %d %d\n",x++,x++,y++);
    
    Output:
    110
    6 5 100

    It's very tempting to wonder how 6+5+100 makes 110.
     
  8. oogabooga

    oogabooga New Member

    Joined:
    Jan 9, 2008
    Messages:
    115
    Likes Received:
    11
    Trophy Points:
    0
    Good point. I was conflating order of execution and order of evaluation.
    But, your cout example is definitely counter-intuitive.
    Code:
    This:
    
        cout << x << ' ' << x++ << endl;
    
    is essentially this: (where op1, op2 stand for "operator")
    
        op1<<( op2<<( op3<<( op4<<( cout, x), ' '), x++), endl);
    
    where the op numbers are assigned like so:
    
        cout << x << ' ' << x++ << endl;
             4    3      2      1
    The outermost view is op1<<( op2<<(), endl). Order of evaluation doesn't matter in this case, since it only matters when the side-effects of evaluating one argument can effect the evaluation of the other.

    In evaluating op2 the order _does_ matter. op2<<( op3<<(), x++)If the arguments are evaluated right-to-left, op3 (and therefore op4) will use the incremented value and op2 will use the pre-incremented value. Hence your result. My compiler gives the more intuitive result (which is actually very misleading).

    I can't understand this, however:
    Code:
        int x = 5, y = 100;
        int z = x++ + x++ + y++;
        printf( "%d\n", z);
    Your compiler prints 110, and so does mine. But surely it should be 111, no matter what the order of evaluation? Associativity should yield: op1+( op2+( x++, x++), y++)
    (where op1 is the second + and op2 is the first + in the actual code).
    Differences in the order of evaluation should pass arguments to op2 as either (5,6) or (6,5), and in either case op2 should yield 11 (+ 100 = 111).
     
    shabbir likes this.
  9. xpi0t0s

    xpi0t0s Mentor

    Joined:
    Aug 6, 2004
    Messages:
    3,009
    Likes Received:
    203
    Trophy Points:
    63
    Occupation:
    Senior Support Engineer
    Location:
    England
    No, the standard doesn't require that x++ means that x is incremented _immediately_ after taking the value, only that x is incremented _some_time_ after taking its value (I think the Standard talks about "sequence points", only requiring that side effects are applied relative in some way to those points). So x++ + x++ could be equivalent to x + (x+1); x+=2, or (x+1) + x; x+=2, but it's equally valid to interpret the code as x + x; x+=2; which is clearly what VS2005 is doing here. This is not wrong, IMHO it's a neat solution because it means (in VS2005) you can effectively ignore postincrement (and presumably also preincrement) operators when trying to figure out what an expression means. The z= expression simply becomes z = x + x + y; x++;x++;y++, but that is by no means the only way it could work, and if the code is ported to a different OS then it could behave differently, thus introducing subtle and probably extremely hard to track down bugs (because even when looking directly at the bug it'll hide behind your understanding of how VS2005 works, it'll only appear once you stop thinking in VS2005 and start thinking in, say, GCC).

    What version of what compiler and OS are you using?
     
  10. oogabooga

    oogabooga New Member

    Joined:
    Jan 9, 2008
    Messages:
    115
    Likes Received:
    11
    Trophy Points:
    0
    Thanks for reminding me about "sequence points". Interestingly, one exists after function arguments are evaluated but before the function is called, but one does _not_ exist after the bulit-in + operator's arguments are evaluated but before the addition is carried out. Of course, a user-defined operator+, being a function, would have such a sequence point.

    At any rate, the moral is to AVOID this kind of thing!

    os: WinXP,SP3
    cp: gcc/g++ 3.4.2 (under Dev-C++)
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice