9

I'm reading bytes from a buffer. But sometimes what I'm reading is a word or longer.

// assume buffer is of type unsigned char *
read_ptr(buffer+(position++))

That's fine but how can I post-increment position by 2 or 4? There's no way I can get the += operator to post-increment, is there?

Reason is, I have this big awful expression which I want to evaluate, while at the same time incrementing the position variable.

I think I came up with my own solution. I'm pretty sure it works. Everyone's gonna hate it though, since this isn't very readable code.

read_ptr(buffer+(position+=4)-4)

I will then make this into a macro after testing it a bit to make sure it's doing the right thing.

IN CONCLUSION:

Don't do this. It's just a bad idea because this is the sort of thing that generates unmaintainable code. But... it does turn out to be quite easy to convert any pre-incrementing operator into a post-incrementing one.

Steven Lu
  • 41,389
  • 58
  • 210
  • 364
  • 4
    Don't do that. Write the code to be clear and easy to read. Abusing the operators like that will only make you cry when the application blows up. – Martin York Mar 19 '11 at 06:51
  • 1
    Note that incrementing a pointer doesn't not necessarily mean that the new value for the pointer is a 1 byte difference. – tJener Mar 19 '11 at 06:53
  • 1
    And, more importantly, it will make _us_ cry if we ever have to maintain that monstrosity. You should always assume that the guy who inherits your code is a psychopath who knows where you live :-) – paxdiablo Mar 19 '11 at 07:01
  • After all the responses, seeing that edit made me facedesk. =( – tJener Mar 19 '11 at 07:02
  • Thanks everyone for excellent comments. On this site, sometimes it feels like a miss when people nitpick every single potential problem with anything I come up with. Then I realize that all the people who read this site will benefit from that, not just me. And that is why SO rules. – Steven Lu Mar 19 '11 at 07:03
  • @tJener -- I'm just trying to get this to work. It's definitely true that this is in many ways an example of Bad Coding. But it doesn't hurt to know that it's possible to write such an expression. For the application I am working on, even if the code being spit out by the preprocessor is an undecipherable mess, it's okay because my macros and their semantics are well-formed. – Steven Lu Mar 19 '11 at 07:09
  • my macros and their semantics are well-formed That just made my cry. The problem is that the cpp macros are pure text substitutions and thus are rarely ever safe thus making macros a very brittle way to write code. THe solution is 1) Don;t make it a macro. 2) Use two lines of code. You are never getting paid to write the least lines of code. – Martin York Mar 19 '11 at 07:15
  • @paxdiablo: And he owns an axe. – Martin York Mar 19 '11 at 07:19
  • @Martin, I guess I'm just trying to have too much fun with the language. Exploring the realm of the possible, if you will. Forgive me. – Steven Lu Mar 19 '11 at 07:23
  • @Steven Lu: C++ is huge you will never learn it all (I am still learning). Ignore the pre--processor (it is two dangerous and unstable) learn the other parts of the language. – Martin York Mar 19 '11 at 16:01
  • I used your `read_ptr(buffer+(position+=4)-4)`, I think it's much better than using macros, and pretty much readable too. – LPVOID May 09 '21 at 11:03

8 Answers8

4

how can I post-increment position by 2 or 4?

You can't post-increment a variable by 2 or 4 but you can use the following (in your case)

read_ptr(buffer+position); position += 2;

Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
  • That is not post-increment, Prasoon! – Nawaz Mar 19 '11 at 06:51
  • 1
    And that becomes _so_ much better (as in, we don't need to go to the standard to check if order is guaranteed) if you just replace that `,` with a `;`. I know, it's a few more electrons on your monitor or ink on your paper, but isn't that worth it for the readability? :-) – paxdiablo Mar 19 '11 at 07:04
  • @paxdiablo : But the effect would be same, isn't it? However as you mentioned as far as readability is concerned `;` is much better. – Prasoon Saurav Mar 19 '11 at 07:06
  • 2
    @Prasoon, that "isn't it?" is the problem. I would have to go look up the standard to see if `,` was a sequence point, guaranteeing order. I _know_ that `;` will guarantee it, `,` _may_ guarantee it but my years are too advanced for me to worry about it unnecessarily :-) But, since you changed it, +1. – paxdiablo Mar 19 '11 at 07:11
  • 1
    "I would have to go look up the standard to see if , was a sequence point" - so the question is whether we're coding for maintenance programmers who know what the comma operator does, or maintenance programmers who don't. This is a general problem in C++, I think, "what can we assume about the competence of: (a) typical, (b) worst-likely-case, programmers. The most obvious answer, "they know the same as me", is wrong, and the second-most obvious, "they know nothing" is too limiting given the power of C++ to do clever but slightly-obscure things. – Steve Jessop Mar 19 '11 at 11:58
  • Of course in this case there's no advantage of a comma over a semi-colon, since we're not in a context where we need to write a single expression. Which is probably why people have to look up what the comma-operator means - it's so rarely appropriate that people aren't familiar with it. Again because C++ is full of obscure cleverness. – Steve Jessop Mar 19 '11 at 12:01
4

Although, I would not recommend this solution, but if you don't want to change this line in your code:

read_ptr(buffer+(position++));

And you still want to post-increment position by 2, then define position as Index position(2); where the type Index is defined here, and also shown the usage:

struct Index
{
    int step;
    int value;
    Index(int s=1, int v=0): step(s), value(v) {}
    Index operator++(int) 
    { 
       Index prev(step, value); 
       value += step; 
       return prev;
    }
    operator int() { return value; }
};

int main() {
        char arr[] = "1234567890" ;

        cout <<"Increment by 2" <<endl;
        Index i2(2); //increment by 2
        cout << *(arr + (i2++)) << endl;
        cout << *(arr + (i2++)) << endl;
        cout << *(arr + (i2++)) << endl;
        cout << *(arr + (i2++)) << endl;

        cout <<"Increment by 3" <<endl;        
        Index i3(3); //increment by 3
        cout << *(arr + (i3++)) << endl;
        cout << *(arr + (i3++)) << endl;
        cout << *(arr + (i3++)) << endl;
        cout << *(arr + (i3++)) << endl;
        return 0;
}

Output:

Increment by 2
1
3
5
7
Increment by 3
1
4
7
0

Working Example : http://ideone.com/CFgal

Note: I would still not suggest this solution in real life project. It's more like puzzle :D

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    Wow. Now this is taking it to another level. It's definitely more readable than my solution I came up with... – Steven Lu Mar 19 '11 at 07:13
  • 1
    @Steven: If it's puzzle or playing around with C++, then you can do such gymnastic. But don't do that in real project! – Nawaz Mar 19 '11 at 07:16
  • indeed. Is there a way to have a parameterizable postincrement operator though? Like, redefine the `+=` operator to get it to post- rather than pre-increment by whatever the right operand is. – Steven Lu Mar 19 '11 at 07:18
  • @Steven: Yes. You can overload `operator+` also. – Nawaz Mar 19 '11 at 07:25
3

The += operator would be a separate statement (not post or pre increment). You could use the following line:

func(buffer + position); position += 2;
David Cravey
  • 151
  • 1
  • 4
3

You don't; you break it up into more than one line. There is no reason to stuff everything into one line here.

read_ptr( buffer + position );
position += n;
Ed S.
  • 122,712
  • 22
  • 185
  • 265
  • 1
    "Post-increment" implies the two lines should be switched. – cHao Mar 19 '11 at 06:51
  • The reason to stuff everything into one line is if it is used as an expression rather than just a statement. – Steven Lu Sep 19 '12 at 19:33
  • @StevenLuL Except that's not a real requirement. There is no reason you need to shove this all into one line and, if you do, you'll be worse off for it. – Ed S. Sep 19 '12 at 19:49
2

Well, I did answer my question in the edit... Basically what I wanted was a single expression which evaluates to the original value but has a side effect of incrementing by an arbitrary amount. Here are some macros.

#define INC(x,inc) (((x)+=(inc))-(inc))
#define INC2(x) INC(x,2)
#define INC4(x) INC(x,4)
#define INC8(x) INC(x,8)
Steven Lu
  • 41,389
  • 58
  • 210
  • 364
1

If position were a pointer to int16 or int32, incrementing it would add 2 or 4, respectively.

Ilkka
  • 2,644
  • 1
  • 23
  • 27
  • Yes, I think an alternate way to achieve what I wanted (kind of) is to increment the pointer itself, as long as it is the appropriate type. Then the `++` operator may be used. – Steven Lu Mar 19 '11 at 07:15
1

In C++, you can easily write a function to perform a post-style double-increment:

template <typename T>
T inc2(T &t) {
    T r(t);
    ++t; // or t++ if you want to respect inconsistently-overloaded operators,
    ++t; // but I wouldn't bother.
    return r;
}

read_ptr(buffer+inc2(position))

In C it's slightly more awkward:

size_t inc2(size_t *s) { // or whatever type you're using
    size_t r = *s;
    (*s) += 2;
    return r;
}

read_ptr(buffer+inc2(&position))

You can cover the 4 case as well by making it an additional function parameter, or perhaps an additional template parameter in the C++ case.

There's a second question, whether it's worth pursuing this style of programming in C++ or in C, where you do so much in a single statement. Avoiding side-effects can make the code easier to understand, even though it comes out longer.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
0

A slightly more generalized version of Steve Jessop's answer to accept all kind of increment steps.

template <auto Step>
constexpr auto post_increment(auto& lvalue)
{
    auto copy = lvalue;
    lvalue += Step;
    return copy;
}

If you explicity need to call operator++ instead of operator+= :

template <auto I>
constexpr auto post_increment_helper(auto& lvalue)
{
    lvalue++; // or ++lvalue
    if constexpr (I > 1)
        post_increment_helper<I - 1>(lvalue);
}

template <auto Step>
constexpr auto post_increment(auto& lvalue)
{
    auto copy = lvalue;
    post_increment_helper<Step>(lvalue);
    return copy;
}

Application :

int a = 4;
auto value = post_increment<5>(a);
std::cout << a << ' ' << value << '\n'; // prints 9 4
Arthur R.
  • 323
  • 2
  • 7