Trying to combine statements, failing miserably.......

Hi all,

I've been playing with a small function:

char *buffer_print (char *buf, char *str, uint64_t *siz)
{
        char *ptr; /* pointer to buffer */
        uint64_t len = strlen (str); /* length of incoming string */

        *siz += len; /* update total size */

        ptr = buf = (char *) realloc (buf, *siz * sizeof (char *)); /* new buffer = old buffer + new size */

        ptr += *siz; /* move pointer to end of re-allocated buffer */
        *ptr = 0; /* null terminate last character */
        ptr -= len; /* move pointer to start of newly allocated area */

        while (len--) { /* copy incoming string to new area */
                ptr[len] = str[len];
        }
        return buf; /* return pointer to complete buffer */
}

These three lines of code are driving me nuts:

        ptr += *siz; /* move pointer to end of re-allocated buffer */
        *ptr = 0; /* null terminate last character */
        ptr -= len; /* move pointer to start of newly allocated area */

I wanted to try to combine them all into one line. I know it's hard to read, bad programming practice, etc... don't scold me.... I don't intend to do it that way... I'm asking because I TRIED to do it for the heck of it and couldn't get it right!

I figured I would just put it all inside parentheses and it would work... I tried this:

__ ((ptr += *siz) = 0) -= len__

doesn't work.

Ah-ha! I see my mistake!

__ (*(ptr += *siz) = 0) -= len;__

Nope....... OH WAIT!!

__ &(*(ptr += *siz) = 0) -= len__

Still nope..... WHAT THE HECK????????

I must be missing something simple and obvious........ but I'm not seeing it.

Any ideas?

Thanks,

-- Roger

I suspect people may be more inclined to put some thought into it if there was a point to the exercise :), but I'm sure someone will accept the challenge.


Rob

Are commas allowed?

Hmmm, failing miserably meets coding badly.... that's going to work! 8)

Graynomad:
I suspect people may be more inclined to put some thought into it if there was a point to the exercise :), but I'm sure someone will accept the challenge.


Rob

What's "the point" of climbing a mountain? :slight_smile:

Are commas necessary?

JimboZA:
Hmmm, failing miserably meets coding badly.... that's going to work! 8)

HA! I laughed out loud. Literally. :slight_smile:

Krupski:

JimboZA:
Hmmm, failing miserably meets coding badly.... that's going to work! 8)

HA! I laughed out loud. Literally. :slight_smile:

Well I'm glad I managed to brighten someone's day so far....

I can do it in one line.

ptr += *siz; *ptr = 0; ptr -= len;

What do I win?

Ah, but in all seriousness, let's think through your problem. I think the problem you're running into is that when you try to put all the statements together, you're losing your reference back to ptr. Let's say that ptr is in memory location 10 and your string is starting at memory location 20 and has a length of 5.

*(ptr += *siz) = 0;

Should work fine. (ptr += *siz) updates memory location 10 by adding siz to it. So memory location 10 used to hold the value 20; now it holds the value 25. That operation completes and returns the value assigned, which is 25. So the parentheses evaluate to 25. Now we have:

*25 = 0;

And that works fine. *25 causes the program to look in memory location 25 and then we assign that location the value 0. Now here's the key: WHAT IS RETURNED FROM THAT OPERATION?

uint64_t len = strlen (str); /* length of incoming string */

Really? You're just a glutton for punishment!

        ptr += *siz; /* move pointer to end of re-allocated buffer */
        *ptr = 0; /* null terminate last character */
        ptr -= len; /* move pointer to start of newly allocated area */

I don't think you can do it. You are pretty much restricted to one assignment per statement, except for what you can accomplish with ++ and -- (neither of which will what you want.)

You can only do x += y or x = y if x is an actual variable with an address; you can't do if x is an expression (whose result is probably some temporary location.)

You DO realize that the terseness of your source code has very little to do with the efficiency of the code that the compiler will produce, right?

Hmm. The compiler let me do pinMode(led+=4, OUTPUT);
I think I find that ... disturbing. I really hope that you can't do (ptr-=len)[len+*siz] = 0;
(OMG, it did compile...)

I think I find that ... disturbing. I really hope that you can't do (ptr-=len)[len+*siz] = 0;

One of my favourite C "quirks"

int array [10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};

void setup() 
{
  int index = 3;
  Serial.begin (9600);
  Serial.println (index [array]);
} 

void loop() 
{}

westfw:

uint64_t len = strlen (str); /* length of incoming string */

Really? You’re just a glutton for punishment!

I originally tested the “print to buffer” code in 64 bit Linux (GCC). I wanted to see how much it could take. I had a check for the malloc/realloc failing and I kept on pumping strings at it while watching my memory pool (ram and swapfile).

Finally it failed because I overran the uint32_t I was using, so I switched it to uint64_t and blasted it more.

It ran and ran until it ate up all my ram, all my swapfile and a little while longer, then finally the realloc() failed by returning a NULL.

I looked at my swap partition with a hex editor raw and found 16 gigabytes of “This is a test” filling it!

I kept on adding zeros to the test loop… I had something like “for x=0; x < 10000000000; x++” I lost track of how many zeros I had.

Anyway, that’s why I had uint64_t in there… and I forgot to change it back to a more sane uint16_t for my Arduino use. :slight_smile:

joshuabardwell:
Ah, but in all seriousness, let’s think through your problem. I think the problem you’re running into is that when you try to put all the statements together, you’re losing your reference back to ptr. Let’s say that ptr is in memory location 10 and your string is starting at memory location 20 and has a length of 5.

*(ptr += *siz) = 0;

Should work fine. (ptr += *siz) updates memory location 10 by adding siz to it. So memory location 10 used to hold the value 20; now it holds the value 25. That operation completes and returns the value assigned, which is 25. So the parentheses evaluate to 25. Now we have:

*25 = 0;

And that works fine. *25 causes the program to look in memory location 25 and then we assign that location the value 0. Now here’s the key: WHAT IS RETURNED FROM THAT OPERATION?

I see what you mean… and it clearly explains why I couldn’t do what I thought I should be able to do. Thanks for the clear explanation!

– Roger

C/C++ has a defined type for buffer lengths, size_t.

I wasn't aware that "x += y" had a value... I guess it makes sense, since "x = x +y" has a value...

westfw:
I wasn't aware that "x += y" had a value... I guess it makes sense, since "x = x +y" has a value...

You really want to drive yourself (and everyone else around you) crazy, start playing around with statements like: x = x++.

x = x++ should be straightforward I think, but I would never trust it.


Rob

Is it straightforward? Not to everyone.

void f()
{
    int x = 10;
    x = x++;
    Serial.print(x)
}

What is printed? No points if you go test it out before answering!

hmm, without looking at the operator precedence I’d say 11 because the ++ is post increment and that normally means post the other operations. So the assignment happens then x gets incremented.

But I’m probably wrong, which is the very reason not to do this in real code.

I haven’t run the code, what is the answer? Actually wouldn’t it be 11 either way?


Rob