a[i] = a[j]... Dangerous?

S

s0suk3

I'm a bit unclear whether a statement such as 'a = a[j];' causes
undefined behavior or some other abnormalities. A statement such as
'a = a[i++];' would definitely cause problems because of the double
use and side effect of 'i'. But in the former case, will the double
use of the array 'a' cause problems? Or will the right operand
('a[j]') of the assignment be evaluated first and then safely assigned
to the right operand ('a')?

Thanks
 
W

Walter Roberson

Kaz Kylheku said:
Note that a = a is well-defined, from which it follows that a = a[j]
is well defined even if i == j.


I don't seem to recall at the moment... if a is an array of
volatile sig_atomic_t and while the statement a = a; is
being executed, there is a signal handler fired which changes
a, what is the "well defined" result?
 
C

CBFalconer

I'm a bit unclear whether a statement such as 'a = a[j];' causes
undefined behavior or some other abnormalities. A statement such as
'a = a[i++];' would definitely cause problems because of the
double use and side effect of 'i'. But in the former case, will the
double use of the array 'a' cause problems? Or will the right
operand ('a[j]') of the assignment be evaluated first and then
safely assigned to the right operand ('a')?


Yes. However a pointer to a _may_ be computed before the value
of a[j] is derived. Your expression is safe.
 
A

August Karlstrom

I'm a bit unclear whether a statement such as 'a = a[j];' causes
undefined behavior or some other abnormalities. A statement such as
'a = a[i++];' would definitely cause problems because of the double
use and side effect of 'i'. But in the former case, will the double
use of the array 'a' cause problems? Or will the right operand
('a[j]') of the assignment be evaluated first and then safely assigned
to the right operand ('a')?

Thanks


In the assignment

a = a[j];

neither a nor a[j] has any side effects so it is certainly a
well-defined statement.


August
 
V

vippstar

On Jul 3, 2:34 am, "Robbie Hatley"
I use something like the above in production code at work,
to periodically move the right-most 80% of an array to the
far left, freeing up space on the right. A FIFO buffer;
only the most recent data is retained, due to space limitations:

int blat[800];
... do some stuff ...
// shift data left when buffer gets full:
if (BufferIsFull())
{
for ( i = 0 ; i < 700 ; ++i )
{
// Discard oldest 100 bytes and shift newest 700 leftward,
// freeing 100 bytes on right side of array:
blat = blat[i+100];
}

}


Just use memmove()

memmove(blat, &blat[100], 700 * sizeof *blat);
 
S

santosh

Robbie said:
Robbie said:
int blat[800];
... do some stuff ...
// shift data left when buffer gets full:
if (BufferIsFull())
{
for ( i = 0 ; i < 700 ; ++i )
{
// Discard oldest 100 bytes and shift newest 700 leftward,
// freeing 100 bytes on right side of array:
blat = blat[i+100];
}
}


Just use memmove()
memmove(blat, &blat[100], 700 * sizeof *blat);


I'd probably seen "memmove" in the libc header before, but using
it for that application simply never occurred to me.

And even after reading the instructions for memmove, I like my
version better, because it's more obvious what's happening:

for ( i = 0; i < 700 ; ++i ) blat = blat[i+1]; // TRANSPARENT

Whereas with memmove, you can't "see under the hood":

memmove(blat, &blat[100], 700 * sizeof *blat); // OPAQUE

I even doubt if the compiled code is faster for memmove.
I'd guess it just uses a for loop. And if it does any
error checking, it could even be slower. (Though in
either case, we're talking maybe about 1 microsecond
every 20 minutes or so. Cheap.)


The standard library memmove can take advantage of any special block
memory copy instructions that the hardware may have, using assembler.
Your replacement cannot do so.

Having said that I have observed in some tests that a custom written
memmove (also memcpy) is actually faster than the one provided by the
standard library, if the code is compiled with optimisations enabled.
This is because the C library on my machine is compiled to run on all
Intel processors from the 80x386 onwards while my custom memmove is
optimised for the specific processor model in operation. The difference
though is minuscule, and shows up only for large copies or intensive
loops.
 
V

vippstar

I'd probably seen "memmove" in the libc header before, but using
it for that application simply never occurred to me.

And even after reading the instructions for memmove, I like my
version better, because it's more obvious what's happening:

for ( i = 0; i < 700 ; ++i ) blat = blat[i+1]; // TRANSPARENT

Whereas with memmove, you can't "see under the hood":

memmove(blat, &blat[100], 700 * sizeof *blat); // OPAQUE

I even doubt if the compiled code is faster for memmove.
I'd guess it just uses a for loop. And if it does any
error checking, it could even be slower. (Though in
either case, we're talking maybe about 1 microsecond
every 20 minutes or so. Cheap.)

What other functions of standard C have you replaced with inline code?
It's bad practise, prone to errors and unproductive.
 
V

vippstar

vippstar said:
Robbie Hatley wrote:
I'd probably seen "memmove" in the libc header before, but using
it for that application simply never occurred to me.
And even after reading the instructions for memmove, I like my
version better, because it's more obvious what's happening:
for ( i = 0; i < 700 ; ++i ) blat = blat[i+1]; // TRANSPARENT
Whereas with memmove, you can't "see under the hood":
memmove(blat, &blat[100], 700 * sizeof *blat); // OPAQUE
I even doubt if the compiled code is faster for memmove.
I'd guess it just uses a for loop. And if it does any
error checking, it could even be slower. (Though in
either case, we're talking maybe about 1 microsecond
every 20 minutes or so. Cheap.)

What other functions of standard C have you replaced with inline
code?

Misquote. I didn't "replace" memmove with anything. As I said,
it never occured to me to use that function (at the time I wrote
the program, about 1 year ago). But even if I had known about
it at the time, I wouldn't have used it, because the hand-written
version is just as short and more transparent.
It's bad practise...

Not necessarily. If it's more clear, I'd call it GOOD practice.
... prone to errors ...

Not necessarily. If the hand-written version is simple, it's
generally no more "prone to error" than a version using a call
to a library function.

Specifically, in the "for-loop vs memmove" case you quote,
the library function is more error prone, because you have to
get three different arguments correct for it to work right.
... and unproductive ...

Nonsense. If it's more clear to the reader, then it's MORE
productive, because it takes the reader less time to understand,
and REDUCES chance of errors due to reader misunderstanding.
(Hint: the reader may be someone other than the original author.)

Don't get me wrong, I use std library functions all the time.
But if I can do the same thing with a single, simple line of
easy-to-understand home-spun code, i'll use the home-spun
instead, because it's more TRANSPARENT:

<snip example>

This group is for C discussions. Clearly you need to be taught the
basics of programming, which I don't think I can teach you in a post
or two. I'll ignore the rest of your replies for this particular
matter, it's likely that a flame war will come out of it without
anything important discussed.
 
K

Kaz Kylheku

vippstar said:
Robbie said:
I'd probably seen "memmove" in the libc header before, but using
it for that application simply never occurred to me.

And even after reading the instructions for memmove, I like my
version better, because it's more obvious what's happening:

for ( i = 0; i < 700 ; ++i ) blat = blat[i+1]; // TRANSPARENT

Whereas with memmove, you can't "see under the hood":

memmove(blat, &blat[100], 700 * sizeof *blat); // OPAQUE

I even doubt if the compiled code is faster for memmove.
I'd guess it just uses a for loop. And if it does any
error checking, it could even be slower. (Though in
either case, we're talking maybe about 1 microsecond
every 20 minutes or so. Cheap.)


What other functions of standard C have you replaced with inline
code?


Misquote. I didn't "replace" memmove with anything. As I said,
it never occured to me to use that function (at the time I wrote
the program, about 1 year ago). But even if I had known about
it at the time, I wouldn't have used it, because the hand-written
version is just as short and more transparent.
It's bad practise...

Not necessarily. If it's more clear, I'd call it GOOD practice.
... prone to errors ...

Not necessarily. If the hand-written version is simple, it's
generally no more "prone to error" than a version using a call
to a library function.

Specifically, in the "for-loop vs memmove" case you quote,
the library function is more error prone, because you have to
get three different arguments correct for it to work right.
... and unproductive ...

Nonsense. If it's more clear to the reader, then it's MORE
productive, because it takes the reader less time to understand,
and REDUCES chance of errors due to reader misunderstanding.
(Hint: the reader may be someone other than the original author.)

Don't get me wrong, I use std library functions all the time.
But if I can do the same thing with a single, simple line of
easy-to-understand home-spun code, i'll use the home-spun
instead, because it's more TRANSPARENT:


Transparency is a desireable property in computer science, when
it refers to a lack of unwanted interference in data communication,
or storage access.

The kind of transparency you are talking about here simply
refers to an inline expansion of something that is abstract
to one of its possible implementation.

All you are doing is burdening the reader with more responsibility.
// YES:
for ( i = 0; i < 700 ; ++i ) blat = blat[i+1];


If we include the declaration of i, this is a 19 node
abstract syntax tree.

Note that we ca make a small change to the above such that
its meaning radically changes.

for ( i = 0; i < 700 ; ++i ) blat += blat[i+1];

Now it's no longer doing a memmove. So you see the reader has
to analyze the code carefully; or else such a little
detail can easily be missed.
// NO:
memmove(blat, &blat[100], 700 * sizeof *blat);

This is a 10 node abstract syntax tree. Only 9 if we change
&blat[100] to blat + 100.

You're saying it's okay to bloat up code by a factor of 1.9
to avoid using a library function.

And that's just the increase in raw synactic complexity.
There is an increase in semantic complexity also.

The meaning of the code is ``copy this much data from here
to there''. The memcpy call simply states that meaning!
It's a primitive, well-understood operation.

The expanded algorithm does /not/ just state that meaning;
the meaning emerges from the relationship of the individual
steps of the algorithm, as it unfolds in time.
I save library functions for things which can NOT be easily
handled by hand-written code, such as:

// Could do this by hand, but this is MUCH easier:
if (strcomp(str1, str2)) {......}

The function is called strcmp, not strcomp. (Are you sure you use it?)

The above code can be inlined with a syntactic bloat of over 3.

This, of course, is worse than 1.9, but not much:

// 5 node syntax tree

if (strcmp(s1, s2)) statement;

// 16 node syntax tree

while (*s1 && *s2)
if (*s1++ != *s2++) {
statement;
break;
}

The professional programmer won't tolerate any increase in syntactic
complexity for the sake of avoiding the use of a standard library function.
The exception would be when he is optimizing.
 
W

Willem

Kaz Kylheku wrote:
) The function is called strcmp, not strcomp. (Are you sure you use it?)

Perhaps he's speaking of some non-standard function that compares
case-insensitively (similar to the also non-standard strcasecmp)

) The professional programmer won't tolerate any increase in syntactic
) complexity for the sake of avoiding the use of a standard library function.
) The exception would be when he is optimizing.

In which case he should (IMO) keep the library function call that he's
replacing in a comment.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
B

Ben Bacarisse

Robbie Hatley said:
Willem said:
... he [Robbie Hatley] should (IMO) keep the library function
call that he's replacing in a comment....

Misquote. I never replaced any library function call. I wrote
the code in question from scratch, electing not to use any
library function calls.

I did not read it as you have edited it. The exchange was:

| ) The professional programmer won't tolerate any increase in syntactic
| ) complexity for the sake of avoiding the use of a standard library function.
| ) The exception would be when he is optimizing.
|
| In which case he should (IMO) keep the library function call that he's
| replacing in a comment.

To me, the "he" refers to "the professional programmer" not to you in
person as your edit of the quote seems to suggest. The discussion had
drifted into a general exchange about what to do ("keep the original")
in the (now hypothetical) case where one *has* replaced a library
call. At any rate, when I read the message you replied to, I did not
read it a referring to your code anymore.
 
J

jacob navia

Mark McIntyre wrote:
[big snip]
But surely you must agree that
memmove(a,b);
is quicker and clearer to read than 100 lines of hand-crafted code.

It is quicker and clearer but also completely wrong.

The prototype for memmove is:
void * memmove(void *, const void *, size_t);

You missed the size_t argument.

Should I deduce that writing library functions is as error prone
as inlining the code?

:)
 
K

Kaz Kylheku

All three arguments are also present in the inline code.

Wow, Friday article appears out of Teranews black hole the following Wednesday!

Strangly, it's still not visible on their server!
 
C

CBFalconer

Kaz said:
Wow, Friday article appears out of Teranews black hole the
following Wednesday!

Strangly, it's still not visible on their server!

Teranews has that habit. It appears about every two weeks or so.
Then they propagate the whole schmeer after a three to five day
delay. Recently they had even more failings, so I switched to
motzarella, and all seems fine so far. When I first used Teranews
they didn't have that delay problem.
 
C

CBFalconer

CBFalconer said:
Teranews has that habit. It appears about every two weeks or so.
Then they propagate the whole schmeer after a three to five day
delay. Recently they had even more failings, so I switched to
motzarella, and all seems fine so far. When I first used
Teranews they didn't have that delay problem.

PS: Teranews has also taken to stealing the Organization slot in
the headers. A further nuisance.
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top