Double increment question.

R

Robbie Hatley

Hello, group. I've been doing too much C++ programming lately, and
I'm starting to become rusty at some aspects of the C way of doing
things, esp. efficient low-level data copies.

Specificially, I just wrote the following, but I don't know if this
is safe:

void Func(char* left, char* right)
{
chat temp_left [17] = {'\0'};
chat temp_right [17] = {'\0'};
int i;
char *ptr1, *ptr2;

/* ... do some stuff ... */

/* Copy the left part to temp_left: */
ptr1 = temp_left;
ptr2 = left;
while (ptr2 < right) *ptr1++ = *ptr2++; // WILL THIS WORK???

/* ... do some other stuff ... */

return;
}

I'm pretty sure that's a conceptually sound way of copying the characters
starting at address "left", up-to-but-not-including address "right",
to array "temp_left".

But my question is, will I get into trouble with that double increment?
Is it guaranteed that (*ptr2) will always get assigned to (*ptr1) before
either increment occurs???

Sorry if this seems like a dorky question. I'm rusty.

--
Cheers,
Robbie Hatley
East Tustin, CA, USA
lone wolf intj at pac bell dot net
(put "[usenet]" in subject to bypass spam filter)
home dot pac bell dot net slant earnur slant
 
R

Richard Riley

Robbie Hatley said:
Hello, group. I've been doing too much C++ programming lately, and
I'm starting to become rusty at some aspects of the C way of doing
things, esp. efficient low-level data copies.
while (ptr2 < right) *ptr1++ = *ptr2++; // WILL THIS WORK???
Is it guaranteed that (*ptr2) will always get assigned to (*ptr1) before
either increment occurs???

Yes. Same as in C++ when dealing with char pointers isnt it?
 
S

spibou

Robbie said:
Hello, group. I've been doing too much C++ programming lately, and
I'm starting to become rusty at some aspects of the C way of doing
things, esp. efficient low-level data copies.

Specificially, I just wrote the following, but I don't know if this
is safe:

void Func(char* left, char* right)
{
chat temp_left [17] = {'\0'};
chat temp_right [17] = {'\0'};
int i;
char *ptr1, *ptr2;

/* ... do some stuff ... */

/* Copy the left part to temp_left: */
ptr1 = temp_left;
ptr2 = left;
while (ptr2 < right) *ptr1++ = *ptr2++; // WILL THIS WORK???

/* ... do some other stuff ... */

return;
}

I'm pretty sure that's a conceptually sound way of copying the characters
starting at address "left", up-to-but-not-including address "right",
to array "temp_left".

I assume chat was meant to be char. I assume also i is used
in the part of the code not given.
But my question is, will I get into trouble with that double increment?
Is it guaranteed that (*ptr2) will always get assigned to (*ptr1) before
either increment occurs???

Strictly speaking , what is guaranteed is that the location ptr2 points
to
before the increment will be assigned the value from the location ptr1
points to before the increment. But whether this assignment occurs
before the pointers have been inceremented is up to the implementation.

Spiros Bousbouras
 
B

BubbaGump

Hello, group. I've been doing too much C++ programming lately, and
I'm starting to become rusty at some aspects of the C way of doing
things, esp. efficient low-level data copies.

Specificially, I just wrote the following, but I don't know if this
is safe:

void Func(char* left, char* right)
{
chat temp_left [17] = {'\0'};
chat temp_right [17] = {'\0'};
int i;
char *ptr1, *ptr2;

/* ... do some stuff ... */

/* Copy the left part to temp_left: */
ptr1 = temp_left;
ptr2 = left;
while (ptr2 < right) *ptr1++ = *ptr2++; // WILL THIS WORK???

/* ... do some other stuff ... */

return;
}

I'm pretty sure that's a conceptually sound way of copying the characters
starting at address "left", up-to-but-not-including address "right",
to array "temp_left".

But my question is, will I get into trouble with that double increment?
Is it guaranteed that (*ptr2) will always get assigned to (*ptr1) before
either increment occurs???

Sorry if this seems like a dorky question. I'm rusty.


You find breaking up the operations into a form that's more obvious to
be objectionable?

while (ptr2 < right) {
*ptr1 = *ptr2;
ptr1++;
ptr2++;
}
 
R

Robbie Hatley

Richard Riley said:
Thanks.

Same as in C++ when dealing with char pointers isnt it?

If it works that way with the one, I suppose it does with the
other. However, my usual way of coping strings in C++ is:

std::string str1 ("Fred"); // make string str1 containing "Fred"
std::string str2 (str1); // make string str2 and copy str1 to str2

A bit simpler than in C. :)

--
Cheers,
Robbie Hatley
East Tustin, CA, USA
lone wolf intj at pac bell dot net
(put "[usenet]" in subject to bypass spam filter)
home dot pac bell dot net slant earnur slant
 
R

Robbie Hatley

Robbie said:
Hello, group. I've been doing too much C++ programming lately, and
I'm starting to become rusty at some aspects of the C way of doing
things, esp. efficient low-level data copies.

Specificially, I just wrote the following, but I don't know if this
is safe:

void Func(char* left, char* right)
{
chat temp_left [17] = {'\0'};
chat temp_right [17] = {'\0'};
int i;
char *ptr1, *ptr2;

/* ... do some stuff ... */

/* Copy the left part to temp_left: */
ptr1 = temp_left;
ptr2 = left;
while (ptr2 < right) *ptr1++ = *ptr2++; // WILL THIS WORK???

/* ... do some other stuff ... */

return;
}

I'm pretty sure that's a conceptually sound way of copying the characters
starting at address "left", up-to-but-not-including address "right",
to array "temp_left".

I assume chat was meant to be char. I assume also i is used
in the part of the code not given.

I was typing an excerpt from a larger function. I should have used
copy-'n'-paste instead, then deleted the excess junk. (The "chat" was
actually in the original, though. I'd not tried to compile it yet,
because I was worried about the run-time effects of the increments.)
Strictly speaking , what is guaranteed is that the location ptr2
points to before the increment will be assigned the value from the
location ptr1 points to before the increment. But whether this
assignment occurs before the pointers have been inceremented is up
to the implementation.

That's the important thing. As long as stuff is copied from the
correct source locations to the correct destination locations, all
is well.

--
Cheers,
Robbie Hatley
East Tustin, CA, USA
lone wolf intj at pac bell dot net
(put "[usenet]" in subject to bypass spam filter)
home dot pac bell dot net slant earnur slant
 
F

Flash Gordon

BubbaGump said:
On Tue, 25 Jul 2006 03:31:33 GMT, "Robbie Hatley"

You find breaking up the operations into a form that's more obvious to
be objectionable?

while (ptr2 < right) {
*ptr1 = *ptr2;
ptr1++;
ptr2++;
}

The code posted by Robbie Hatley is idiomatic C, so whether you like it
or not to be competent you have to understand it.
 
R

Richard Heathfield

Robbie Hatley said:
Hello, group. I've been doing too much C++ programming lately, and
I'm starting to become rusty at some aspects of the C way of doing
things, esp. efficient low-level data copies.

Specificially, I just wrote the following, but I don't know if this
is safe:

It isn't, but perhaps not for the reason you imagine.
void Func(char* left, char* right)
{
chat temp_left [17] = {'\0'};
chat temp_right [17] = {'\0'};
int i;
char *ptr1, *ptr2;

/* ... do some stuff ... */

/* Copy the left part to temp_left: */
ptr1 = temp_left;
ptr2 = left;
while (ptr2 < right)

This comparison compares the ptr2 pointer value with a pointer to a
completely different object. Bad idea, unless you know for sure (and how
can you?) that 'right' is actually a pointer into the same object that
'left' points to.

*ptr1++ = *ptr2++; // WILL THIS WORK???

Yes, because ptr1 and ptr2 do not at any time point to the same char. But
even so, wouldn't it be easier to work out how many bytes you want to copy
and just memcpy them?
I'm pretty sure that's a conceptually sound way
Yes...

of copying the characters starting at address "left",

....and yes...
up-to-but-not-including address "right",

....and no, unless you can guarantee that 'right' points into the same
object.
 
C

Chris Dollin

BubbaGump said:
snip)

(fx:snip)

You find breaking up the operations into a form that's more obvious to
be objectionable?

while (ptr2 < right) {
*ptr1 = *ptr2;
ptr1++;
ptr2++;
}

I find the former more obvious than the latter. It's idiomatic, it's
presented compactly enough to see it as a unit, and it's harder to make
the mistake of incrementing the wrong variable or forgetting to
increment a variable.

I'm not really worried about code being inobvious to people who
are new to the language: not all code is suitable for tutorial
use.

The second form is more /explicit/, certainly.
 
R

Robbie Hatley

You find breaking up the operations into a form that's more
obvious to be objectionable?

while (ptr2 < right) {
*ptr1 = *ptr2;
ptr1++;
ptr2++;
}

A few years ago, I would have preferred that, yes. These days,
however, something like:

while (ptr2 < right) *ptr1++ = *ptr2++;

actually looks more "obvious" to me. At least, I understand the intent
of the author instantly. Whether or not the sequence points work out
right in such code is a different matter! It's so easy to make blunders
like that. But my friend Ron, the firmware guru, uses code like that
all the time without having it blow up on him. A matter of experience.

I was just googling "sequence point", trying to find more info on this,
and I ran across http://c-faq.com/ which is, lo and behold, the FAQ for
this group. That site mentions the following two sentences from the
C standard:

Between the previous and next sequence point an object shall
have its stored value modified at most once by the evaluation
of an expression. Furthermore, the prior value shall be accessed
only to determine the value to be stored.

After staring at those for a while I think I understand them.
If I'm getting the idea right, it says:

1. You aren't supposed to alter the same variable twice between
sequence points.
2. If you alter a variable between two sequence points, you're
not supposed to use the original value of that variable for
any purpose other than computing the final value to be stored
back into the variable.

For example, I think the following violates those rules:

int main()
{
int y=0;
int x=7;
y = 2*x + x++; // violates sentence 2?
printf("y = %d", y); // prints 21? or 22?

y=0;
x=7;
y = x++ + x++; // violates sentences 1 and 2?
printf("y = %d", y); // prints 14? or 15?

return 0;
}

Looks to me like both of those calculations are undefined.
Do I have that right?

--
Cheers,
Robbie Hatley
East Tustin, CA, USA
lone wolf intj at pac bell dot net
(put "[usenet]" in subject to bypass spam filter)
home dot pac bell dot net slant earnur slant
 
R

Robbie Hatley

Richard said:
Robbie Hatley said:

This comparison compares the ptr2 pointer value with a pointer to a
completely different object. Bad idea, unless you know for sure (and how
can you?) that 'right' is actually a pointer into the same object that
'left' points to.

That's actually not a danger here. It's taken care of in the chopped-out
part. Also, with one exception, the only caller of Func is Func
(it's recursive), so it controls what "left" and "right" point to.
Yes, because ptr1 and ptr2 do not at any time point to the same char. But
even so, wouldn't it be easier to work out how many bytes you want to copy
and just memcpy them?

memcpy did occur to me, yes. But I'm writing a program which I want to
be as small and fast as possible, so I'm doing things "manually".
If the MyProgram.exe file is 47 bytes and processes 8TB of data in 3.5ns,
that wouldn't be too small or fast for my taste. (Pardon my exageration.)
I'm not even #including <stdlib.h>. The only #include is <stdio.h>, and
if I could figure out how to print to stdout without that, I would.

--
Cheers,
Robbie Hatley
East Tustin, CA, USA
lone wolf intj at pac bell dot net
(put "[usenet]" in subject to bypass spam filter)
home dot pac bell dot net slant earnur slant
 
R

Richard Heathfield

Robbie Hatley said:

For example, I think the following violates those rules:

int main()
{
int y=0;
int x=7;
y = 2*x + x++; // violates sentence 2?
Yes.

printf("y = %d", y); // prints 21? or 22?

Or nothing. Or "banana". Quite apart from the undefined behaviour you
invoked in the previous line, you're calling a variadic function without a
valid prototype in scope.
y=0;
x=7;
y = x++ + x++; // violates sentences 1 and 2?

Yes.
 
R

Richard Heathfield

Robbie Hatley said:
Richard Heathfield wrote:



memcpy did occur to me, yes. But I'm writing a program which I want to
be as small and fast as possible,

memcpy is likely to be faster than byte-by-byte copying for even moderate
volumes of data. Why? Because it's got a fighting chance of being
implemented as hand-rolled assembly language, packed to the gunwales with
performance-enhancing drugs.
so I'm doing things "manually".

So why not go the whole hog and use pencil and paper? ;-)
If the MyProgram.exe file is 47 bytes and processes 8TB of data in 3.5ns,
that wouldn't be too small or fast for my taste. (Pardon my exageration.)
I'm not even #including <stdlib.h>.

How does its omission speed up your program?
The only #include is <stdio.h>, and
if I could figure out how to print to stdout without that, I would.

int putchar(int);

int main(void)
{
int ch = '\n';
putchar(ch);
return 0;
}

But omitting stdio.h won't speed up your program either.
 
F

Flash Gordon

Robbie Hatley wrote:

A few years ago, I would have preferred that, yes. These days,
however, something like:

while (ptr2 < right) *ptr1++ = *ptr2++;

actually looks more "obvious" to me. At least, I understand the intent
of the author instantly. Whether or not the sequence points work out
right in such code is a different matter! It's so easy to make blunders
like that. But my friend Ron, the firmware guru, uses code like that
all the time without having it blow up on him. A matter of experience.

Knowledge of the language as well.
I was just googling "sequence point", trying to find more info on this,
and I ran across http://c-faq.com/ which is, lo and behold, the FAQ for
this group.

It is very good reading material.
> That site mentions the following two sentences from the
C standard:

Between the previous and next sequence point an object shall
have its stored value modified at most once by the evaluation
of an expression. Furthermore, the prior value shall be accessed
only to determine the value to be stored.

After staring at those for a while I think I understand them.
If I'm getting the idea right, it says:

1. You aren't supposed to alter the same variable twice between
sequence points.
2. If you alter a variable between two sequence points, you're
not supposed to use the original value of that variable for
any purpose other than computing the final value to be stored
back into the variable.

For example, I think the following violates those rules:

int main()
{
int y=0;
int x=7;
y = 2*x + x++; // violates sentence 2?
Correct.

printf("y = %d", y); // prints 21? or 22?

Or anything else or nothing at all. Violating the sequence point rule
means that *anything* is allowed to happen, including it causing your
mother-in-law to move in permanently. A slightly more plausible but very
damaging scenario that could occur is wrecking the processor due to a
bus collision. Imagine a processor with multiple data buses, so it can
simultaneously write to multiple memory location in its cache. Imagine
further that the processor does not validate that parallel accesses are
actually to different locations. Since the compiler is not required to
do anything in particular it could generate code that wrote the result
of incrementing x simultaneously with reading x to calculate 2*x, and
this could damage the processor.
y=0;
x=7;
y = x++ + x++; // violates sentences 1 and 2?

Yes. It is also one of the "classic" examples.
printf("y = %d", y); // prints 14? or 15?

Or it could do anything else.
return 0;
}

Looks to me like both of those calculations are undefined.
Do I have that right?

Yes. All yo have not got is that the results of undefined behaviour can
be even stranger than you can imagine.
 
E

Eric Sosman

Robbie said:
[...]
memcpy did occur to me, yes. But I'm writing a program which I want to
be as small and fast as possible, so I'm doing things "manually". [...]

Digging a hole in the ground is a wearisome and tedious
task, and I'd like it to take as little time as possible.
That's why I told that guy with the backhoe to go somewhere
else, threw away my silly old shovel, and am now "doing things
manually" by scrabbling in the dirt with my fingernails. ;-)

More seriously, it seems more than a little likely that
you are committing the sin of premature optimization. Until
and unless you have MEASURED a performance problem -- not
hypothecated, not supposed, not "it stands to reason-ed" --
until you have made MEASUREMENTS it is irresponsible folly to
micro-optimize.

"Premature optimization is the root of all evil."
-- D.E. Knuth

"We follow two rules in the matter of optimization:
Rule 1: Don't do it.
Rule 2 (for experts only): Don't do it yet."
-- M.A. Jackson

"More computing sins are committed in the name of efficiency
(without necessarily achieving it) than for any other single
reason, including blind stupidity."
-- W.A. Wulf

In other words, I'm not the only person crying that ab initio
micro-optimization is folly; smart people do so, too. Be smart.
 
F

Frederick Gotham

Robbie Hatley posted:

while (ptr2 < right) *ptr1++ = *ptr2++; // WILL THIS WORK???


Yes, assuming the function is invoked somewhat like the following:

int main(void)
{
char const str[] = "Hello, I'm a dog.";

Func(str, str[7]);
}

If "right" were to refer to a totally different string, you'd have undefined
behaviour.
 
R

Richard Heathfield

Frederick Gotham said:
Robbie Hatley posted:

while (ptr2 < right) *ptr1++ = *ptr2++; // WILL THIS WORK???


Yes, assuming the function is invoked somewhat like the following:

int main(void)
{
char const str[] = "Hello, I'm a dog.";

Func(str, str[7]);

Either you meant &str[7] or str + 7. And the const breaks the Func call,
since Func takes char *, not const char * (see OP).
 
F

Frederick Gotham

Richard Heathfield posted:
int main(void)
{
char const str[] = "Hello, I'm a dog.";

Func(str, str[7]);

Either you meant &str[7] or str + 7.


Indeed I meant:

str + 7

And the const breaks the Func call,
since Func takes char *, not const char * (see OP).


....but the function signature is broken : )
 
B

BubbaGump

The code posted by Robbie Hatley is idiomatic C, so whether you like it
or not to be competent you have to understand it.

Yes, it's good to understand it so go explain away, but I was
questioning why he was trying to use it.

Also, I don't believe competence requires complete understanding.
 
F

Flash Gordon

BubbaGump said:
Yes, it's good to understand it so go explain away, but I was
questioning why he was trying to use it.

Because he wants to write idiomatic C?
Also, I don't believe competence requires complete understanding.

Not complete understanding of everything, no, but to be competent in a
language you have to understand the common idioms, and *dst++ = *src++
is an *extremely* common idiom in C and so needs to be understood.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top