Why have i++; i--; right after each other?
Asked Answered
F

4

166

I was looking at the source code for nmap that was released in 1997 and I noticed this section of code that looks a little odd to me:

int i=0, j=0,start,end;
char *expr = strdup(origexpr);
ports = safe_malloc(65536 * sizeof(short));
i++;                                         /* <<<<<< */
i--;                                         /* <<<<<< */
for(;j < exlen; j++) 
  if (expr[j] != ' ') expr[i++] = expr[j]; 
expr[i] = '\0';

Why would you have i++; and then i--; right after each other? i is 0, then i++ turns i to 1. After that, i-- turns i to 0.

Link to original source code. Search for:

i++;
i--;

Can anyone explain what this is for?

Facesaving answered 28/3, 2020 at 13:51 Comment(13)
There is no reason.Underarm
Ask the author.Cornstarch
I'd guess they were part of some experimental or debugging code, which the author forgot to remove afterward.Crocoite
In a kernel code that could be a tiny delay, or a compiler optimization bug fixNotarize
@RingØ: It probably won't work to produce a delay, because the compiler will optimize it out.Crocoite
@NateEldredge I assumed we're talking about an old code (1997, see answer), and compilers at the time.....Notarize
The reason is obviously to confuse you, that's the only purpose :-) There's a small chance that this works around some compiler bug in some ancient compiler, in that case there should have been comment telling us this reason.Lightning
@RingØ: For fun I tried it with gcc 1.27, circa 1988, on godbolt: godbolt.org/z/yYyFrQ. (It doesn't work with modern system headers so I had to declare all the standard library functions myself.) But with -O it does indeed optimize out those statements.Crocoite
There might have been some code in-between, which has then been deleted?Carreon
I was thinking, "Might have been that the data type used to be a custom class that overrode an operator..." only to see that it's C, not C++.Shelashelagh
It means the programmer was paid by the line...Anglesite
If i was a memory mapped i/o port then adding and subtracting would actually do something. So there are cases where you would write code like that. Of course, it isn't true because if that was the use case i should have been defined as volatile so that the reads and writes wouldn't be optimised out.Stoned
Quite probably, there was a line of code, a function call between the i++ and the i--; The function call was removed temporarily, and was never restored.Vintager
H
154

This was a bug. These lines together result in i being unchanged, so they shouldn't have been there.

The linked article that introduced nmap was published on September 1 1997. If you look at the SVN repository for nmap at https://svn.nmap.org/nmap, the initial revision checked in on February 10 1998 does not have those lines:

int i=0, j=0,start,end;
char *expr = strdup(origexpr);
char *mem = expr;

ports = safe_malloc(65536 * sizeof(short));
for(;j < exlen; j++) 
  if (expr[j] != ' ') expr[i++] = expr[j]; 
expr[i] = '\0';

So this is something the author found and fixed between publishing the initial nmap source code and the initial checkin to SVN.

Homework answered 28/3, 2020 at 14:39 Comment(6)
Hmm that page is missing <pre> tags around the article, too; Chrome's inspector reveals how that leads to some document mangling during DOM construction ;)Drab
Is it really a bug if it does not cause any unintended/unexpected behaviour?Ozoniferous
It confuses readers, which is completely unintended. I'd say it is clearly a bug. ;-)Reseau
@Reseau Wikipedia does not agree with you, but this blog post does, and I'm inclined to as well :-)Ozoniferous
Now if i wasn't an int but some fancy class with operator overloads, it's possible (though unlikely and generally a sign of poor coding practices) that this could have some side effects. (Only applies if this were C++ of course.)Hurty
Maybe worth noting that in some contexts (memory-mapped IO), changing a variable can have external effects.Jillianjillie
G
41

It's useless. It does absolutely nothing.

If I were to speculate it's probably the remains of some debugging code that was used during development.

I'm guessing that either one of i++ or i-- was introduced in one change and the other was introduced in another.

I have no way to find the point of introduction, though, because there was no revision history between the initial source release and the first SVN revision.

Gurrola answered 28/3, 2020 at 15:6 Comment(1)
I think the speculation about debugging code is accurate. I've seen so many different kind of debugging code just to get breakpoints where you expect them.Plectognath
T
9

For a non-optimizing compiler, or one that recognized hardware side effects, the i++; i-- sequence would cause i to be read from memory, then re-written, regardless of the path taken through the for loop and nested if.

In parallel processing, sometimes compiler hacks are taken to ensure a code sequence uses its own local copies of variables rather than global copies.

Since the example is a code snippet, one cannot determine the compiler used, the expected operating system/hardware, nor whether this is in a code sequence/function that is possible to be executed as an independent thread.

In simpler systems, I've temporarily forced changes to variables to exercise the trap feature in a debugging environment. If that were the case, the author may have forgotten to remove the code when development was completed.

Together answered 31/3, 2020 at 2:43 Comment(4)
then why not just declare it as volatile?Sedda
The declaration of i as a local variable is shown in the code above, and there is no way it can be accessed by another thread at the point where the i++; i-- lines are.Matty
@Sedda I rather think he means i is forced to be non-volatile. I haven't dealt with threading in C or C++ though, so I have no clue how it could be treated as volatile and how i++; i-- would suppress that.Ulbricht
volatile has other purposes besides thread-safety. It can also be used while debugging to ensure the compiler won't optimize it away.Sedda
A
2

I will suggest you to check the updated code only. If you use (i = 2+1) right after that (i-1) that make no sense . The value of i remains unchanged. You can try it using any c or c++ compiler. or even in any other language it is same. Run the code in compiler.

Actomyosin answered 8/4, 2020 at 12:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.