473,473 Members | 1,976 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

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

I'm a bit unclear whether a statement such as 'a[i] = a[j];' causes
undefined behavior or some other abnormalities. A statement such as
'a[i] = 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[i]')?

Thanks
Jun 30 '08 #1
29 1327
s0****@gmail.com wrote:
I'm a bit unclear whether a statement such as 'a[i] = a[j];' causes
undefined behavior or some other abnormalities.
It doesn't.

--
pete
Jul 1 '08 #2
In article <20****************@gmail.com>,
Kaz Kylheku <kk******@gmail.comwrote:
>Note that a[i] = a[i] is well-defined, from which it follows that a[i] = 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[i] = a[i]; is
being executed, there is a signal handler fired which changes
a[i], what is the "well defined" result?
--
"Eightly percent of the people in the world are fools and the
rest of us are in danger of contamination." -- Walter Matthau
Jul 1 '08 #3
s0****@gmail.com wrote:
>
I'm a bit unclear whether a statement such as 'a[i] = a[j];' causes
undefined behavior or some other abnormalities. A statement such as
'a[i] = 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[i]')?
Yes. However a pointer to a[i] _may_ be computed before the value
of a[j] is derived. Your expression is safe.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Jul 1 '08 #4
s0****@gmail.com wrote:
I'm a bit unclear whether a statement such as 'a[i] = a[j];' causes
undefined behavior or some other abnormalities. A statement such as
'a[i] = 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[i]')?

Thanks
In the assignment

a[i] = a[j];

neither a[i] nor a[j] has any side effects so it is certainly a
well-defined statement.
August
Jul 1 '08 #5

<s0****@gmail.comwrote:
I'm a bit unclear whether a statement such as 'a[i] = a[j];' causes
undefined behavior or some other abnormalities. A statement such as
'a[i] = 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[i]')?
"a[i] = a[j];" is legal.

The only surprises it might have in store is if you don't keep
the ranges of numbers over which i and j vary non-overlapping.
If they overlap, stuff will get over-written. If that's what
you intended, great; otherwise, it's a problem.

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[i] = blat[i+100];
}
}

--
Cheers,
Robbie Hatley
lonewolf aatt well dott com
www dott well dott com slant user slant lonewolf slant
Jul 2 '08 #6
On Jul 3, 2:34 am, "Robbie Hatley"
<see.my.signat...@for.my.email.addresswrote:
<snip>
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[i] = blat[i+100];
}

}
Just use memmove()

memmove(blat, &blat[100], 700 * sizeof *blat);
Jul 2 '08 #7
On 2008-07-02, Robbie Hatley <se**************@for.my.email.addresswrote:
"a[i] = a[j];" is legal.

The only surprises it might have in store is if you don't keep
the ranges of numbers over which i and j vary non-overlapping.
If they overlap, stuff will get over-written.
a[i] is ``stuff''.

a[i] is overwritten.

Therefore, stuff is overwritten.

What may be a surprise is that a[j] is overwritten, if i == j.
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[i] = blat[i+100];
}
}
Why would you write loops that reinvent memmove?

#include <string.h>

/* ... */

memmove(blat + i, blat + i + 100, 700 * sizeof *blat);

** Posted from http://www.teranews.com **
Jul 3 '08 #8

<vi******@gmail.comwrote:
Robbie Hatley wrote:

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[i] = 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[i] = 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.)

--
Cheers,
Robbie Hatley
lonewolf aatt well dott com
www dott well dott com slant user slant lonewolf slant
Jul 3 '08 #9
Robbie Hatley wrote:
>
<vi******@gmail.comwrote:
>Robbie Hatley wrote:
>
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[i] = 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[i] = 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.

Jul 3 '08 #10
On Jul 3, 10:37 pm, "Robbie Hatley"
<see.my.signat...@for.my.email.addresswrote:
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[i] = 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.
Jul 3 '08 #11

"vippstar" wrote:
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[i] = 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:

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

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

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)) {......}

// This one, i don't even know if it CAN be done by hand,
// and even if it could, the home-spun version probably
// wouldn't be portable:
printf("Number of employees = %d\n", NumEmp);

--
Cheers,
Robbie Hatley
lonewolf aatt well dott com
www dott well dott com slant user slant lonewolf slant
Jul 3 '08 #12
On Jul 4, 1:47 am, "Robbie Hatley"
<see.my.signat...@for.my.email.addresswrote:
"vippstar" wrote:
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[i] = 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.
Jul 3 '08 #13
[rolling one's own memmove code]

Robbie Hatley said:
>
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.)
Most readers will find it easier to read memmove calls than hand-rolled
loops. Hint: for any code that is read by at least three people, most
readers are 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:
The great thing about standard library functions is that they're easy to
understand because we've all used them a brazillion times before - so we
can see at a glance what the code does. If you replace the code with, say,
this:
>
// YES:
for ( i = 0; i < 700 ; ++i ) blat[i] = blat[i+1];
....we have to think more carefully about whether the code is right.
>
// NO:
memmove(blat, &blat[100], 700 * sizeof *blat);
But this doesn't do the same thing! Use this instead:

memmove(blat, blat + 1, 700 * sizeof *blat);
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 C language doesn't define a strcomp function.
// This one, i don't even know if it CAN be done by hand,
// and even if it could, the home-spun version probably
// wouldn't be portable:
printf("Number of employees = %d\n", NumEmp);
It can, and it would be. But that doesn't mean it would be *wise*.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jul 4 '08 #14
On 2008-07-03, Robbie Hatley <se**************@for.my.email.addresswrote:
>
"vippstar" wrote:
>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[i] = 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[i] = 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[i] += 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.

Jul 6 '08 #15
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
Jul 7 '08 #16

Who let this troll in here?

"<vi******@gmail.com>" spewed:
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.
On Usenet, I only talk to people who are capable of cordial,
on-topic, non-ad-hominem conversations. Clearly, you are not.

::: killfiles vi******@gmail.com :::

Buh-bye.

--
Cheers,
Robbie Hatley
lonewolf aatt well dott com
www dott well dott com slant user slant lonewolf slant

Jul 7 '08 #17

Richard Heathfield wrote:
Robbie Hatley said:

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

...we have to think more carefully about whether the code
is right....
Typo. Scroll up a couple of messages, and you'll see it
started out like this:

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

Dunno how the two zeros got cut out.
// NO:
memmove(blat, &blat[100], 700 * sizeof *blat);

But this doesn't do the same thing!
It does, if you put the zeros back.
Use this instead:

memmove(blat, blat + 1, 700 * sizeof *blat);
No, a correct version would be:

memmove(blat, blat + 100, 700 * sizeof *blat);

But I MUCH prefer:

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

Because it says EXACTLY what it does, and EXACTLY how
it does it, in 52 characters, 14 of which are whitespace.

Whereas, memmove is an opaque "black box".
The C language doesn't define a strcomp function.
Typo. strcmp. Don't be silly; you can intuit that.
// This one, i don't even know if it CAN be done by hand,
// and even if it could, the home-spun version probably
// wouldn't be portable:
printf("Number of employees = %d\n", NumEmp);

It can, and it would be. But that doesn't mean it would
be *wise*.
Of course it's not wise. I never said it was. In fact,
I said the opposite. There are times and places for
library functions. Printing things is one of those.
But in my opinion, shifting some data 100 bytes to the
left is not.

--
for (i = 0; i < 700; ++i) blat[i] = blat[i+100]; /* :-P */
Robbie Hatley
lonewolf aatt well dott com
www dott well dott com slant user slant lonewolf slant
Jul 7 '08 #18

"Kaz Kylheku" <kk******@gmail.comwrote:
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.
Misquote. I never "expanded" memmove. memmove was never in
the program to begin with! You really do need to READ what
you're replying to, before replying to it.

The for loop in question wasn't "one possible implimentation
of memmove"; it wan't an attempt to impliment memmove at all!
It was written for one specific application in which I needed
to shift some data in a "partial-overwrite" fashion, while
insuring the following:

1. That the over-write destroys ONLY the oldest 100 bytes.
2. That the exact method was as I desired.
3. That the method be transparent to the reader.

A simple 1-line for loop, easily understandable by even
a newbie at C, served admirably.
All you are doing is burdening the reader with more
responsibility.
No. Library functions require looking-up syntax and
semantics, whereas for loops and pointers are part of the
basic language. So in those rare cases where the hand-
written version is simpler (clearer to the reader) than
a library function call, I tend to write it by hand.
... the reader has to analyze the code carefully; or else
such a little detail can easily be missed...
Always true when reading code, REGARDLESS of whether library
functions are used or not.
... This is a 10 node abstract syntax tree....
I think you're over-technicalizing a simple thing.
I just go by what WORKS, and what is CLEAR, "abstract
syntax trees" not withstanding.
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.
Some don't grok C. C'est la vie. If my boss hires someone
who can't understand for loops, that's his loss, not mine.
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.
A mostly-true platitude. But like all platitudes, it has
it's limits of applicability, and if over-relied-on, can
be as harmful as it is helpful.

--
Cheers,
Robbie Hatley
lonewolf aatt well dott com
www dott well dott com slant user slant lonewolf slant
Jul 8 '08 #19

"Willem" <wi****@stack.nlwrote:
... 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.

Where are people get this "replaced a library function call"
stuff from? I never said that anywhere! I believe it was the
person calling hirself "vipstarr" who said I "replaced a library
function call", not me. I've placed that person in my killfile
due to obnoxiousness, trolling, and apparently-on-purpose misquotes.
Maybe this person is the finest fellow in the world and is just in
a bad mood today, but on Usenet, I can only judge by what I read.

This is the danger of replying to a reply to a reply to a reply
to a reply to a reply to something an OP said. Gets confusing,
doesn't it? You end up misquoting and misunderstanding things.
Hence, best not to do that.

--
Cheers,
Robbie Hatley
lonewolf aatt well dott com
www dott well dott com slant user slant lonewolf slant
Jul 8 '08 #20
"Robbie Hatley" <se**************@for.my.email.addresswrites:
"Willem" <wi****@stack.nlwrote:
>... 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.

--
Ben.
Jul 8 '08 #21
Robbie Hatley wrote:
"Kaz Kylheku" <kk******@gmail.comwrote:
>All you are doing is burdening the reader with more
responsibility.

No. Library functions require looking-up syntax and
semantics, whereas for loops and pointers are part of the
basic language.
Ok, but in the case of the standard library, the programmer should be
familiar enough with the type of function you refer to, for its syntax
to be as familiar as the basic language.
So in those rare cases where the hand-
written version is simpler (clearer to the reader) than
a library function call, I tend to write it by hand.
But note that this comes at a potential cost of erroneous results &
slower performance, harder maintenance and more possibility of failing
to catch a tricky case.

As a junior maintenance droid some time ago I was once tasked with
cleaning up some code that had been 'optimised' by a self-styled
uberprogrammer. This consisted of removing overly complex use of the
language, rerolling gratuitously unrolled loops, replacing hand-crafted
functions with normal library functions etc.

The reason I had to do this was that a) hardly anyone on the team could
understand the code and b) it was generating wrong answers in obscure
but customer-relevant cases. A side-effect of my work was that it ran
faster.
>... the reader has to analyze the code carefully; or else
such a little detail can easily be missed...

Always true when reading code, REGARDLESS of whether library
functions are used or not.
But surely you must agree that
memmove(a,b);
is quicker and clearer to read than 100 lines of hand-crafted code.

>... This is a 10 node abstract syntax tree....

I think you're over-technicalizing a simple thing.
I just go by what WORKS, and what is CLEAR, "abstract
syntax trees" not withstanding.
Just to warn you, OVER capitalising is often regarded as the start of a
slippery slope!

>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.

Some don't grok C. C'est la vie.
That's not Kaz's point. He's discussing the algo.
If my boss hires someone
who can't understand for loops, that's his loss, not mine.
Well yes and no - all programmers should strive to write understandable
code, as not everyone is as smart and clueful as themselves. And as a
'boss' myself I take the view that my staff should care about whether
they're being productive for the /company/ - which includes writing code
that is maintainable by less expert than themselves. Overcomplex and
oversmart code isn't productive...
>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.

A mostly-true platitude. But like all platitudes, it has
it's limits of applicability, and if over-relied-on, can
be as harmful as it is helpful.
Your response is also a platitude, of course ! :-)
--
Mark McIntyre

CLC FAQ <http://c-faq.com/>
CLC readme: <http://www.ungerhu.com/jxh/clc.welcome.txt>
Jul 8 '08 #22
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?

:-)

--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
Jul 8 '08 #23
Robbie Hatley said:
>
Richard Heathfield wrote:
>Robbie Hatley said:
>
// YES:
for ( i = 0; i < 700 ; ++i ) blat[i] = blat[i+1];

...we have to think more carefully about whether the code
is right....

Typo. Scroll up a couple of messages, and you'll see it
started out like this:

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

Dunno how the two zeros got cut out.
Neither do I.
>
// NO:
memmove(blat, &blat[100], 700 * sizeof *blat);

But this doesn't do the same thing!

It does, if you put the zeros back.
But not if you don't. I don't recall seeing the zeros at all.
>
>Use this instead:

memmove(blat, blat + 1, 700 * sizeof *blat);

No, a correct version would be:

memmove(blat, blat + 100, 700 * sizeof *blat);
Now that you mention the zeros, yes. But my code was a correct rewrite of
the code I could see.
>
But I MUCH prefer:

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

Because it says EXACTLY what it does, and EXACTLY how
it does it, in 52 characters, 14 of which are whitespace.
memmove(blat, blat + 100, 700 * sizeof *blat);

says EXACTLY what it does, and explains EXACTLY why it isn't important how
it does it, in 46 characters, 7 of which are whitespace.
Whereas, memmove is an opaque "black box".
Its semantics are clearly described in the Standard.
>The C language doesn't define a strcomp function.

Typo. strcmp. Don't be silly; you can intuit that.
Getting it right is a good habit to get into. Assuming that other people
will interpret your typos in the way you intended is a bad habit to get
into, and one that can cost millions of LCUs.
// This one, i don't even know if it CAN be done by hand,
// and even if it could, the home-spun version probably
// wouldn't be portable:
printf("Number of employees = %d\n", NumEmp);

It can, and it would be. But that doesn't mean it would
be *wise*.

Of course it's not wise. I never said it was.
Right. Neither is rolling your own memmove.
In fact,
I said the opposite. There are times and places for
library functions. Printing things is one of those.
Actually, there are times when you can't use the standard routines (because
they don't give the desired effect). For example, if you want to pop a
dialog box onto the screen with your message centred over an OK button,
printf probably isn't going to cut it. So I/O is one of those places where
you very often /do/ need to roll your own. But your specific example,
where you ask for a portable workaround, would simply be a rewriting of
printf to avoid calling printf, and that's silly.
But in my opinion, shifting some data 100 bytes to the
left is not.
Actually, shifting data around is exactly the kind of thing where you do
want to use the standard library, because it's exactly the kind of thing
that each implementor can spend hours and days and weeks and months
optimising for their target platform. Even if by some miracle you did
manage to outperform an implementor's memmove on one platform using
portable code, it's very unlikely that your speed gain would persist
across platforms.

If in doubt, use the Standard Library. If I were maintaining your stuff,
I'd spend a few minutes trying to work out why you didn't call memmove,
and then I'd rip your stuff out and put a memmove call in there. I'd also
send out an email to the rest of the project team, suggesting that they
keep half an eye out for unnecessary stdlib rewrites.

But, of course, I'm not maintaining your stuff - something for which I am
profoundly grateful. :-)

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jul 8 '08 #24
On 2008-07-03, Robbie Hatley <se**************@for.my.email.addresswrote:
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.
All three arguments are also present in the inline code.
>... 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.
However, your naive reinvention of memmove doesn't have any
of the above attributes.
(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
Writing it all in one line doesn't make it one line.

The way to measure code size is to look at the number of nodes
in the abstract syntax tree.
easy-to-understand home-spun code, i'll use the home-spun
instead, because it's more TRANSPARENT:
The intent of the code is to move a block of so much memory from the
source address to the destination address.

This is exactly expressed in the C language with the function call

memmove(destination_address, source_address, so_much).

There is no need whatsoever for this to be ``transparent'';
it is a well-understood, primitive operation.

Inline code is not transparent; it burdens the reader with the necessity
to understand it.

Transparency in computer science typically refers to the freedom from unwanted
interference in the communication of data, flow of control, or reference to
storage.
// YES:
for ( i = 0; i < 700 ; ++i ) blat[i] = blat[i+1];
The above is incomplete, because i has to be defined somewhere:

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

Someone who is maintaining this code has to analyze the algorithm
to convince himself that it really is just performing a block move.

A slight modification in the code can change it so that it does
something other than a block move. It's easy for a maintainer
to miss such a change:

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

The inline code contains significantly more syntax. If we transliterate
it into a parse tree notation, we get this:

((int i)
(for (= i 0) (< i 700) (++ i))
(= (blat i) (blat (+ i 1))))

This tree contains 19 nodes. If we transliterate the memmove call
to an abstract syntax tree:

memmove(blat, blat + 100, 700 * sizeof *blat);

(memmove blat (+ blat 100) (* 700 (sizeof (* blat))))

We get only 10 nodes. The inline code represents a 1.9 times bloat in raw
syntactic complexity! That doesn't even include the bloat in /semantic/
complexity, namely that the inline code encodes its meaning in an algorithm
from which the meaning emerges as the total effect of many small steps which
must be understood individually and in relation to each other as they
unfold in time, whereas the function call simply /states/ its meaning.
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)) {......}
If you really used strcmp, wouldn't you know what it's called?

And it's actually not that difficult to inline the above by hand.

// 5-node syntax tree

if (strcmp(s1, s2)) statement;

can be written:

// 16-node syntax tree

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

The strcmp version is more than three times smaller. So what you are saying is
that bloating up code by a factor of three is outside of your comfort zone; you
will consider the library function instead. But if the hand-written code
``only'' bloats the syntax by a factor of 1.9, then it's okay to go ahead with
it.

The professional programmer won't tolerate any code bloat caused by eschewing
the use of a suitable standard library function, except when the code is being
optimized.
** Posted from http://www.teranews.com **
Jul 9 '08 #25
On 2008-07-04, Kaz Kylheku <kk******@gmail.comwrote:
On 2008-07-03, Robbie Hatley <se**************@for.my.email.addresswrote:
>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.

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!
Jul 9 '08 #26
Kaz Kylheku wrote:
Kaz Kylheku <kk******@gmail.comwrote:
>Robbie Hatley <se**************@for.my.email.addresswrote:
>>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.

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!
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.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Jul 9 '08 #27
CBFalconer wrote:
Kaz Kylheku wrote:
>Kaz Kylheku <kk******@gmail.comwrote:
>>Robbie Hatley <se**************@for.my.email.addresswrote:

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.

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!

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.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Jul 10 '08 #28

Richard Heathfield wrote:
memmove(blat, blat + 100, 700 * sizeof *blat);
says EXACTLY what it does,
The name "memmove" says VAGUELY what the function does (moves
something in memory), but neglects to mention many aspects, such as
the fact that the standard mandates that memmove() copies memory
contents in such as way that the source bytes are not altered before
writing them to the destination area. For this function's name to
"say EXACTLY what it does", it would need to be renamed to something
like "memory_block_copy_with_protected_source".
and explains EXACTLY why it isn't important how it does it
The standard makes very specific demands on how memmove is to
behave, so "how it does it" does become important.
Whereas, memmove is an opaque "black box".
Its semantics are clearly described in the Standard.
The readership for code I write here at work consists of newbie
programmers who do not possess copies of the standard, and are
unlikely to spend time researching library functions. They're
not going to read the "clear descriptions" in the standard.
So I tend to write to their level.
... shifting data around is exactly the kind of thing where
you do want to use the standard library ... Even if by
some miracle you did manage to outperform an implementor's
memmove on one platform using portable code, it's very unlikely
that your speed gain would persist across platforms.
I never said I was attempting to write for speed. We're talking
about moving a small ammount of data, once every 20 minutes, on
a system with a 32-bit CPU running at 1-2 GHz. Many things in life
strike me as being "important", but trying to save 200nS per each
20 minutes is NOT one of them.

But since you insist, it is quite likely that on any one platform
a simple for loop may be roughly twice as fast as the equivalent
memmove() call. Why? Because the standard insists that memmove()
copy "as if via a temporary". Depending on how it's implimented,
each byte may be copied twice:

// Copy maybe first to temporary array, then to destination:
memmove ( blat, blat + 100, 700 * sizeof *blat );

Whereas with my for loop, there is no doubt: it uses *NO* temporary:

// Copy with no temporary:
for ( i = 0 ; i < 700 ; ++i ) blat[i] = blat[i+100];

If this code had been embedded in an outer loop which ran this code
many times per second, then the for loop might be dramatically
superior to memmove, depending on how the compiler author chose to
impliment memmove.
If in doubt, use the Standard Library.
I was never "in doubt". I spent about 2 seconds considering
whether to call a standard library function, before rejecting it
unreservedly.

In general, std-lib functions often include error-checks and
safeguards which, while helpful in most situations, may be harmful
in others. So I'd say, if "in doubt", study the situation to see
if it has any specific requirements which may need special handling.
If it doesn't, and if a std-lib function is available which will
reduce code complexity and increase clarity, then I agree, call the
std-lib function.
If I were maintaining your stuff, I'd spend a few minutes trying
to work out why you didn't call memmove,
The reasons were personal-preference and audience-consideration,
not technical. You couldn't work out the reasons by inspection.
and then I'd rip your stuff out and put a memmove call in there.
I'd also send out an email to the rest of the project team,
suggesting that they keep half an eye out for unnecessary stdlib
rewrites.
You'd get an angry letter from the boss about "wasting time",
and stoney silence from your co-workers, who would only vaguely
understand your message, and would not take your advice.
But, of course, I'm not maintaining your stuff - something for
which I am profoundly grateful. :-)
It wasn't written for you. If I write something for you to
maintain, I'll write it in a style more to your liking (incl.
heavier use of library functions).

But if I'm copying 100 bytes of data from point A to point B,
I still might use a for loop, depending on the situation. :-)

--
for (i = 0; i < 700; ++i) blat[i] = blat[i+100]; /* :-P */
Robbie Hatley
lonewolf aatt well dott com
www dott well dott com slant user slant lonewolf slant
Jul 14 '08 #29
Robbie Hatley said:
>
Richard Heathfield wrote:
>memmove(blat, blat + 100, 700 * sizeof *blat);
says EXACTLY what it does,

The name "memmove" says VAGUELY what the function does (moves
something in memory),
Perhaps I'm too used to it, then. I think of it as being just as
descriptive as any English word. I don't have to go running to the
dictionary whenever I see the word "cat", and I don't have to go running
to the Standard every time I see the word "memmove".
but neglects to mention many aspects, such as
the fact that the standard mandates that memmove() copies memory
contents in such as way that the source bytes are not altered before
writing them to the destination area.
All of this is well-known. The English word "cat" neglects to mention many
aspects of the cat nature, such as stubbornness, ignoritude, inability (or
refusal) to understand about not jumping on the table, etc. Nevertheless,
when someone says "cat", all these connotations are immediately apparent
to me, without my having to think about it consciously. The same applies
to memmove.

<snip>
>and explains EXACTLY why it isn't important how it does it

The standard makes very specific demands on how memmove is to
behave, so "how it does it" does become important.
Not to the programmer - only to the implementor. The programmer only needs
to know that, if you're copying data that overlap, you should use memmove
rather than memcpy.
The readership for code I write here at work consists of newbie
programmers who do not possess copies of the standard, and are
unlikely to spend time researching library functions.
Scary. I just hope they're not writing anything important.
They're
not going to read the "clear descriptions" in the standard.
So I tend to write to their level.
You would do better to get them to aim for a higher level.
>... shifting data around is exactly the kind of thing where
you do want to use the standard library ... Even if by
some miracle you did manage to outperform an implementor's
memmove on one platform using portable code, it's very unlikely
that your speed gain would persist across platforms.

I never said I was attempting to write for speed.
That is about the only justification (and itself often a spurious one) that
I can think of for reinventing the standard library.
We're talking
about moving a small ammount of data, once every 20 minutes, on
a system with a 32-bit CPU running at 1-2 GHz. Many things in life
strike me as being "important", but trying to save 200nS per each
20 minutes is NOT one of them.
Agreed. A memmove call is quicker to type, quicker to read, and generally
quicker to execute than its hand-rolled loop equivalent. The second of
these reasons is normally the most important.
>
But since you insist, it is quite likely that on any one platform
a simple for loop may be roughly twice as fast as the equivalent
memmove() call. Why? Because the standard insists that memmove()
copy "as if via a temporary". Depending on how it's implimented,
each byte may be copied twice:
Yes, it may - but you'd be hard-pressed to find a mainstream implementation
that did it that way.
>
// Copy maybe first to temporary array, then to destination:
memmove ( blat, blat + 100, 700 * sizeof *blat );

Whereas with my for loop, there is no doubt:
You would do better to trust your implementor (unless you're knowingly
using a lame implementation, in which case change it).
it uses *NO* temporary:

// Copy with no temporary:
for ( i = 0 ; i < 700 ; ++i ) blat[i] = blat[i+100];

If this code had been embedded in an outer loop which ran this code
many times per second, then the for loop might be dramatically
superior to memmove, depending on how the compiler author chose to
impliment memmove.
Since shoving stuff around in RAM is such an important job, I think you'll
find that the implementor has gone to a lot of trouble to make memmove as
efficient as he possibly can.
>
>If in doubt, use the Standard Library.

I was never "in doubt". I spent about 2 seconds considering
whether to call a standard library function, before rejecting it
unreservedly.

In general, std-lib functions often include error-checks and
safeguards which, while helpful in most situations, may be harmful
in others. So I'd say, if "in doubt", study the situation to see
if it has any specific requirements which may need special handling.
If it doesn't, and if a std-lib function is available which will
reduce code complexity and increase clarity, then I agree, call the
std-lib function.
Right - so in this case that'd be memmove.
>If I were maintaining your stuff, I'd spend a few minutes trying
to work out why you didn't call memmove,

The reasons were personal-preference and audience-consideration,
not technical. You couldn't work out the reasons by inspection.
Not all audiences will appreciate your "consideration", though I'm sure it
was kindly meant.
>and then I'd rip your stuff out and put a memmove call in there.
I'd also send out an email to the rest of the project team,
suggesting that they keep half an eye out for unnecessary stdlib
rewrites.

You'd get an angry letter from the boss about "wasting time",
Misdirection of mail is a crime in many jurisdictions; I would feel obliged
to forward the letter to the appropriate recipient.
and stoney silence from your co-workers, who would only vaguely
understand your message, and would not take your advice.
Sturgeon did have a point, didn't he?

<snip>

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jul 14 '08 #30

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

101
by: Bill Cunningham | last post by:
I read an article in a book about Perl and Common Gateway Interface and it mentioned C. It said that C could damage your computer. I don't know wether it meant the standard or compiler issuses. I...
1
by: b83503104 | last post by:
When are they not consistent?
4
by: cesark | last post by:
Hi ! I have important doubts about how to handle the security in asp.net vb.net web forms. Somebody can help me? 1. If you have setting ‘validateRequest=true’ in .net framework1.1, What can...
302
by: Lee | last post by:
Hi Whenever I use the gets() function, the gnu c compiler gives a warning that it is dangerous to use gets(). Is this due to the possibility of array overflow? Is it correct that the program...
6
by: Brendan | last post by:
Hi, I'm trying to mimic the IPC/messaging system of an specific OS in a portable way by using GCC's library. The IPC system uses buffered asynchronous messages, where any thread can send a...
10
by: lovecreatesbea... | last post by:
C stops the conversion from (char **) to (const char **). c-faq.com sec 11.10 has explanation on this point. But, for example, even the conversion from (char *) to (const char *) brings the same...
6
by: Thomas.li | last post by:
Hi, I want to convert CString to LPBYTE like LPBYTE lpByte = (BYTE*)(LPCTSTR)cstring; is it very dangerous to do that?
233
by: Julian | last post by:
'evening. I'm not new to C and have been programming in it since I was 8 but here's a strange problem I've never seen before. When I compile a program from our C course with a windows compiler...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
1
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
1
muto222
php
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.