469,341 Members | 8,254 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,341 developers. It's quick & easy.

c# is a good way to learn c


After working in c# for a year, the only conclusion I can come to is
that I wish I knew c.

All I need is Linux, the gnu c compiler and I can do anything.

Web services are just open sockets hooked up to interfaces.

The Gtk is more than enough gui.

Jul 21 '05
354 13587
> Feh.

Try this code for pretty. This is in MASM/Intel syntax:

mov edx, eax ; edx=0x84838281
shr eax, 16 ; eax=0x00008483
xchg eax, edx ; edx=0x00008483,eax=0x84838281
xchg al, ah ; eax=0x84838182
shl eax, 16 ; eax=0x81820000
xchg dl, dh ; edx=0x00008384
or eax, edx ; eax=0x81828384

There's probably better methods but I've already reduced it to 7
instruction lines by simply coding it by hand. Works like a champ.

I could reduce it to 3 if there's a method to exchange
the 16-bit register ax with the high 32-bits of eax.
However, the obvious choices 'xchg eax,ax' and 'xchg eah,ax'
both fell flat.

Very nice. :-)

But the big question now in modern processors is yours faster?
I do know that some simple instructions that are used more often tends to be
faster than instructions that might have one opcode but not used that much.
And another thing is that that modern processors execute stuff out of order.
So less instructions does not mean necesarely faster performance, but it
could and in your solution it might.

The only way to determin what is faster is to actually measure it.
And then again, it might be processor dependend.
Jul 21 '05 #301
> return * P << 24 | * ++ P << 16 | * ++ P << 8 | * ++ P ; }
does work correctly in GCC. >>

But that's a quirk, of course.
Yes it shoud have worked in my opinion too.
But this is life, nothing is perfect.

I also discovered one time that if you use events in a C++ class VC++ 2002
then you get an access violation if the class happens not to have a
constructor defined and implemented in the header file.
So for week I struggled with that event thing, and funny enough the examples
worked, but mine failed. Then I started to realize looking at the assmbly
code that the variables of those events didn't get initialized. Clearly a
bug in the C++ compiler. Now my code works fine, since I now put a complete
constructor in the headre file. So the code generated is now correct.
At the very Very least, a compiler warning should be thrown !
I fully agree.
Wow, I'm impressed ! So much for my claim that you don't do assembly anymore. In my case it is 15 years old knowledge. I only use it to look at the
generated code to find bugs in my code and to optimize my functions to speed
up without resorting to assembler.
Or to learn a new language, because I can compare it to something I already
know.

And now I do this with IL assembler generated by .NET. One thing I discover
is that properties are not optimized, not inlined so that could explain why
some C# code could be slower. But then again if I look at my C++ code of the
VC++ 2003 Standard, none of my properties gets inlined too. And this
explains why my C++ code and C# code are almost the same speed on the same
computer and the same OS and compiled with the same compiler environment. I
hope that The VS 2005 gets a better optimizer for that.

You added: << I could reduce it to 3 if there's a method to exchange
the 16-bit register ax with the high 32-bits of eax. However,
the obvious choices xchg eax,ax and xchg eah,ax both fell flat. >>

Wow again, You just taught me some x86 assembly:
1. ax is a short.
2. al is ax's low byte.
3. ah is ax's high byte.
4. eax is a long.
In the case of Intel like processors, the ax, eax register gets specialized
for processing things.It is another name for accumulator.
You will discover that any operation is done on that register, so a lot of
code is copying registers to the eax register and then move it back.

Another thing to know is that you cannot access the upper word part of eax.
(or the ebx, ecx, edx)
Only the lower word part that could be split into a high byte and a low
byte.

eax is the 32 bit register
ax is the same as LOWORD(eax)
and al would be like LOBYTE(ax)
and ah would be like HIBYTE(ax)

So to get the HIWORD(eax), you must >> 16 to it ends into the ax part.
Then you can access it.

Typically eax is used for calculating things.
ebx is used as index pointer
ecx is typically used as counter
edx is typically used as destination index pointer.
But in the case of an optimizer compiler you might lose that relationship.

Another thing somethin like this "xor ecx,ecx" is actually saying set
ecx to null.
This notation is only one byte and superfast compared to loading it with a
actual value.

And the reason why the P++ and P-- tends to be faster in C++ is because it
translates to an assembler instruction
inc ebx // P++
dec ebx // P--

While the P=P+1 would probably translate to somthing like this (just
guessing)
//P++
mov eax,ebx
mov ebx,1
add eax,ebx

//P--
mov eax,ebx
mov ebx,1
sub eax,ebx
Olaf taught me that this is moving an int off the stack to ecx

mov ecx, dword ptr [ esp + 18h ]

Yes a local variable located at 18h positions from your return address. :-)
And if you get something like this "mov ecx, dword ptr [ esp - 18h ]"
then it is some parameter passed on from outside your function.

Jul 21 '05 #302
Jeff_Relf wrote:
uint_32 Big_First_32 ( int X ) { uint_8_P P = ( uint_8_P ) & X ;
return * P << 24 | * ++ P << 16 | * ++ P << 8 | * ++ P ; }


I thought it was pretty cool that Ghost basically doused your code with
some shit that was totally Elegant and that makes Ghost a Mogul and you
a Serf.

Prolly if he took the time to read your 'c' code...well less just say
the Machine Got Gaaaame.
Jul 21 '05 #303
Olaf Baeyens wrote:
Feh.

Try this code for pretty. This is in MASM/Intel syntax:

mov edx, eax ; edx=0x84838281
shr eax, 16 ; eax=0x00008483
xchg eax, edx ; edx=0x00008483,eax=0x84838281
xchg al, ah ; eax=0x84838182
shl eax, 16 ; eax=0x81820000
xchg dl, dh ; edx=0x00008384
or eax, edx ; eax=0x81828384

There's probably better methods but I've already reduced it to 7
instruction lines by simply coding it by hand. Works like a champ.

I could reduce it to 3 if there's a method to exchange
the 16-bit register ax with the high 32-bits of eax.
However, the obvious choices 'xchg eax,ax' and 'xchg eah,ax'
both fell flat.


Very nice. :-)

But the big question now in modern processors is yours faster?
I do know that some simple instructions that are used more often tends to be
faster than instructions that might have one opcode but not used that much.
And another thing is that that modern processors execute stuff out of order.
So less instructions does not mean necesarely faster performance, but it
could and in your solution it might.

The only way to determin what is faster is to actually measure it.
And then again, it might be processor dependend.


btw., what's wrong with the BSWAP instruction?

Stefan
Jul 21 '05 #304
> btw., what's wrong with the BSWAP instruction?

And the winneerr isssss!!!!!!!!! STEFAAAAAANNNN!!!!!

He is right, since the 80486 there exist one assembler function that does
that. :-)

<snip>
The bswap instruction, available only on 80486 (yes, 486) and later
processors, converts between 32 bit little endian and big endian values.
This instruction accepts only a single 32 bit register operand. It swaps the
first byte with the fourth and the second byte with the third. The syntax
for the instruction is
bswap reg32where reg32 is an 80486 32 bit general purpose register.
</snip>
Jul 21 '05 #305
This does the trick in VC++ 2003

int iswapped=0;
int iOriginal=0x01234567;
__asm {
mov eax,iOriginal
bswap eax
mov iswapped,eax
}

Which translates to:

mov dword ptr [iswapped],0 // int iswapped=0;
mov dword ptr [iOriginal],1234567h // int iOriginal=0x01234567;
// and now the __asm part
mov eax,dword ptr [iOriginal] // mov eax,iOriginal
bswap eax
mov dword ptr [iswapped],eax // mov iswapped,eax

And in a optimizer compiler: "mov eax,dword ptr [iOriginal]" and "mov dword
ptr [iswapped],eax" might have been stripped away since the variables would
probaly already exist in eax.

So for those that thought that Assembler died, it is still there, absorbed
into the C++ language.
Jul 21 '05 #306

Hi Stefan, You ased: << what's wrong with the BSWAP instruction ? >>

Variations of my Big_First_32() illustrate serious problems
with MS_CPP, not just with Sequence_Points,
but, even more seriously, with how it's /Og switch, Global optimizations,
breaks perfectly legal code.

Spooky would say that BSWAP doesn't work on the PowerPC, or something.

MS_CPP has _byteswap_ulong() which is just a BSWAP instruction:

mov ecx,eax
bswap ecx

I have a cheap_ass Celeron with only a 128 KB L2 cache.
After double_clicking Kelsey.EXE three times in a row, for good measure,
these are the times that I'm getting:
.00445 Seconds, Sum 2147244176424960, _byteswap_ulong( 0 - 999,999 ).
.00608 Seconds, Sum 2147244176424960, Swap_32( 0 - 999,999 ).
.00593 Seconds, Sum 2147244176424960, Big_First_32( 0 - 999,999 ).
.01049 Seconds, Sum 2147244176424960, htonl( 0 - 999,999 ).

http://www.Cotse.NET/users/jeffrelf/Kelsey.EXE
http://www.Cotse.NET/users/jeffrelf/Kelsey.CPP
http://www.Cotse.NET/users/jeffrelf/Kelsey.VCPROJ

#pragma warning( disable: 4244 )
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <StdLib.H>
#include <stdio.h>
#include <IO.H>
#include <Winsock2.H>
#pragma comment( lib, "Ws2_32.LIB")

#define Loop( N ) int J = - 1, LLL = N ; while ( ++ J < LLL )
#define Tics ( QueryPerformanceCounter( ( Quad * ) & _Tics ), _Tics )
#define Secs ( _Secs = Tics / Secnd_Dub )

typedef char * int_8_P ;
typedef unsigned char uint_8 ; typedef uint_8 * uint_8_P ;
typedef unsigned __int32 uint_32 ;
typedef LARGE_INTEGER Quad ;

double Secnd_Dub, _Secs, Mark ; __int64 _Tics, Secnd ;

uint_32 Big_First_32 ( int & X ) { uint_8_P B = ( uint_8_P ) & X ;
return * B << 24 | B [ 1 ] << 16 | B [ 2 ] << 8 | B [ 3 ]; }

uint_32 Swap_32 ( int X ) {
return uint_8( X ) << 24 | uint_8( X >> 8 ) << 16
| uint_8( X >> 16 ) << 8 | uint_8( X >> 24 ); }

main() {
QueryPerformanceFrequency( ( Quad * ) & Secnd ); Secnd_Dub = Secnd ;
FILE * fp = fopen( "AA.TXT", "w" );
const int Times = 1000 * 1000 ;

__int64 X = 0 ; Mark = Secs ;
{ Loop( Times ) X += _byteswap_ulong( J ); } double Dur = Secs - Mark ;

__int64 X2 = 0 ; Mark = Secs ;
{ Loop( Times ) X2 += Swap_32( J ); } double Dur2 = Secs - Mark ;

__int64 X3 = 0 ; Mark = Secs ;
{ Loop( Times ) X3 += Big_First_32( J ); } double Dur3 = Secs - Mark ;

__int64 X4 = 0 ; Mark = Secs ;
Loop( Times ) X4 += htonl( J ); double Dur4 = Secs - Mark ;

char SecStr [ 99 ] ;
sprintf( SecStr, "%1.5f" , Dur );
fprintf( fp, "%s Seconds, Sum %I64d, _byteswap_ulong( 0 - 999,999 ).\n"
, SecStr + ( * SecStr == '0' ), X );

sprintf( SecStr, "%1.5f" , Dur2 );
fprintf( fp, "%s Seconds, Sum %I64d, Swap_32( 0 - 999,999 ).\n"
, SecStr + ( * SecStr == '0' ), X2 );

sprintf( SecStr, "%1.5f" , Dur3 );
fprintf( fp, "%s Seconds, Sum %I64d, Big_First_32( 0 - 999,999 ).\n"
, SecStr + ( * SecStr == '0' ), X3 );

sprintf( SecStr, "%1.5f" , Dur4 );
fprintf( fp, "%s Seconds, Sum %I64d, htonl( 0 - 999,999 ).\n"
, SecStr + ( * SecStr == '0' ), X4 ); fclose( fp ); }

Jul 21 '05 #307

Hi Olaf, You wrote: << This does the trick in VC++ 2003
int iswapped=0; int iOriginal=0x01234567;
__asm {
mov eax,iOriginal
bswap eax
mov iswapped,eax }

Which translates to:

mov dword ptr [iswapped],0 // int iswapped=0;
mov dword ptr [iOriginal],1234567h // int iOriginal=0x01234567;
// and now the __asm part
mov eax,dword ptr [iOriginal] // mov eax,iOriginal
bswap eax
mov dword ptr [iswapped],eax // mov iswapped,eax

And in a optimizer compiler: mov eax,dword ptr [iOriginal]
and mov dword ptr [iswapped],eax might have been stripped away
since the variables would probaly already exist in eax.

So for those that thought that Assembler died,
it is still there, absorbed into the C++ language. >>

Too bad you don't have MS_CPP_Pro,
You might look for a so_called used or OEM copy on eBay.

I don't trust /Og, wouldn't use it for serious products, too fickle,
but it is fun to play with.

Jul 21 '05 #308

Hi Olaf, Re: * ++ P << 16 | * ++ P << 8 and how | doesn't, but should,
provide a so_called Sequence_Point in C_99, gcc or MS_CPP_7_1,

You told me: << Yes it shoud have worked in my opinion too.
But this is life, nothing is perfect. >>

I think MicroSoft won't implement extra Sequence_Points
for fear of becomming too incompatible with the other compilers.
Which is a real shame, as, no doubt, it's the cause of many a mysterious bug.

I think MS should just add a bunch of additional Sequence_Points
and tell the others to either catch up or go fish.

Speaking of compiler faults,
I say C# is wrong to not support printf(), #define, #include, etc.
Not because I care about old code, but becuase I prefer those operatives.

C++/C#'s String/cout/STL can be handy, no doubt,
but I still prefer doing my own memory management, dynamic lists, etc.
As my HTM_TXT.CPP demonstrates, LoopTo() is just pure flexibility:

#define LoopTo( StopCond ) \
while ( Ch && ( Ch = ( uchar ) * ++ P ) \
&& ! ( Ch2 = ( uchar ) P [ 1 ], StopCond ) )

You recounted: <<
I also discovered one time that, if you use events in a C++ class,
VC++ 2002 [ throws ] an access violation if the class happens
not to have a constructor defined and implemented in the header file.
So, for a week, I struggled with that event thing,
and, funny enough, the examples worked but mine failed.
[ Looking at the assmbly code, I saw that ]
the variables of those events [ weren't getting ] initialized.
Clearly a bug in the C++ compiler. Now my code works fine,
since I now put a complete constructor in the header file. >>

Interesting, I wouldn't have thought to check the disassembly like that,
I'll try that the next time I have a hard_to_find bug ( i.e. soon ).

Re: How you use assembly these days, You wrote: <<
In my case it is 15 years old knowledge.
I only use it to look at the generated code to find bugs in my code
and to optimize my functions to speed up without resorting to assembler.
Or to learn a new language,
because I can compare it to something I already know.

And now I do this with IL assembler generated by .NET. >>

The IL assembler sounds cool to me.

You added: << One thing I discover is that properties are not optimized,
not inlined so that could explain why some C# code could be slower.
But then again if I look at my C++ code of the VC++ 2003 Standard,
none of my properties gets inlined too. And this explains
why my C++ code and C# code are almost the same speed on the same computer
and the same OS and compiled with the same compiler environment.
I hope that The VS 2005 gets a better optimizer for that. >>

I have my MS_CPP_Pro inline stuff, even when debugging,
it hasn't been a problem for me.

Re: x86 assembly, you told me: << In the case of Intel like processors,
the ax, eax register gets specialized for processing things.
It is another name for accumulator. >> ... <<
any operation is done with that register, so a lot of code
is copying registers to the eax register and then moving it back.

Another thing to know is that you cannot access the upper word part of eax.
( or the ebx, ecx, edx )
Only the lower word part [ can ] be split into a high byte and a low byte.

eax is the 32 bit register
ax is the same as LOWORD(eax)
and al would be like LOBYTE(ax)
and ah would be like HIBYTE(ax)

So to get the HIWORD(eax), you must >> 16 to [ access ] the ax part.
Then you can access it.

Typically eax is used for calculating things.
ebx is used as index pointer
ecx is typically used as counter
edx is typically used as destination index pointer.
But in the case of an optimizer compiler
you might lose that relationship. >>

What other registers are there, and how are they restricted ?

You added: << Another thing something like this xor ecx,ecx
is actually saying set ecx to null.
This notation is only one byte and superfast
compared to loading it with a actual value. >>

That much I knew already.

Re: mov ecx, dword ptr [ esp + 18h ]

You concluded: <<
Yes a local variable located at 18h positions from your return address. :-)
And if you get something like this mov ecx, dword ptr [ esp - 18h ]
then it is some parameter passed on from outside your function. >>

That's interesting, - is a parameter, thanks.

Jul 21 '05 #309
> Interesting, I wouldn't have thought to check the disassembly like that,
I'll try that the next time I have a hard_to_find bug ( i.e. soon ).
Most of the times I use it if I have complicated one liners, to find out
what instruction in that part is causing the problem.
And now I do this with IL assembler generated by .NET. >>

The IL assembler sounds cool to me.
It is some kind of OOP version of assembler.
But they don't use registers. They use the stack, it is up to the optimizer
to use the most efficient way of register usage.

IL looks something like this (peudo code):

//x=A+B-C
Push A
Push B
Add
Push C
Sub

A little bit like HP calculators would do to.
As far as I see, the generated IL code in C# does not seem to be optimized.
But the JIT might do that optimizing instead, so when I find time I am going
to check into this.
Typically eax is used for calculating things.
ebx is used as index pointer
ecx is typically used as counter
edx is typically used as destination index pointer.
But in the case of an optimizer compiler
you might lose that relationship. >>

What other registers are there, and how are they restricted ?
This is getting too big for the time that I have to explain all this.
You concluded: <<
Yes a local variable located at 18h positions from your return address. :-) And if you get something like this mov ecx, dword ptr [ esp - 18h ]
then it is some parameter passed on from outside your function. >>

That's interesting, - is a parameter, thanks.

Most of the time eax, ebx, ecx and edx is used for the first 4 parameters
that fit in a 32 bit number, like int, short, byte, and pointers/references)
and then they start using parameters pushed on the stack
Most of the time a result is returned in the eax.

But if you use a different calling convention other rules might apply.
Jul 21 '05 #310

Hi Olaf, Re: Push A Push B Add Push C Sub,

I know Forth fairly well, including PostScript.

You told me: << Most of the time eax, ebx, ecx and edx
are used for the first 4 parameters that fit in a 32 bit number,
( like int, short, byte, and pointers/references )
and then they start using parameters pushed on the stack.
Most of the time a result is returned in the eax. >>

Cool, that's good to know, thanks.

Jul 21 '05 #311
In comp.os.linux.advocacy, Jeff_Relf
<Me@Privacy.NET>
wrote
on 15 Apr 2005 04:15:06 GMT
<Je************************@Cotse.NET>:

Hi Spooky, Re: Your mod of the code I showed, You told me: <<
return * P << 24 | * ++ P << 16 | * ++ P << 8 | * ++ P ; }
does work correctly in GCC. >>

But that's a quirk, of course.
The solution would be to modify the MS_CPP and gcc compilers themselves,
as well as the C_2006 standard, to introduce Many more sequence points.

For example,
Each of the following should have it's left_to_right'ness guaranteed,
complete with so_called sequence_points in the obvious places:
1. char Buffer [] = { func(), /* Seq_Pnt */ func(), /* Seq_Pnt */ func() };
2. func( func(), /* Seq_Pnt */ func(), /* Seq_Pnt */ func() );
3. return * ++ P << 16 | /* Seq_Pnt */ * ++ P << 8 ;

At the very Very least, a compiler warning should be thrown !

Re: How I liked the disassembly of the working C++ code I showed,

You replied: << Feh. Try this code for pretty.
This is in MASM/Intel syntax:

mov edx, eax ; edx=0x84838281
shr eax, 16 ; eax=0x00008483
xchg eax, edx ; edx=0x00008483,eax=0x84838281
xchg al, ah ; eax=0x84838182
shl eax, 16 ; eax=0x81820000
xchg dl, dh ; edx=0x00008384
or eax, edx ; eax=0x81828384

There's probably better methods but I've already reduced it to 7
instruction lines by simply coding it by hand. Works like a champ. >>

Wow, I'm impressed ! So much for my claim that you don't do assembly anymore.
I don't. This is a hobby. :-) But I've used it in the past,
in the 8088 PC era (the systems were a *lot* slower then),
and I've had to debug the occasional routine using nothing but.

You added: << I could reduce it to 3 if there's a method to exchange
the 16-bit register ax with the high 32-bits of eax. However,
the obvious choices xchg eax,ax and xchg eah,ax both fell flat. >>

Wow again, You just taught me some x86 assembly:
1. ax is a short.
2. al is ax's low byte.
3. ah is ax's high byte.
4. eax is a long.

Olaf taught me that this is moving an int off the stack to ecx

mov ecx, dword ptr [ esp + 18h ]
Hmm...that's a simple one, at that:

push ebp
move ebp, esp
mov ax, word ptr 8(ebp)
xchg al, ah
lsh eax, 16
mov ax, word ptr 10(ebp)
xchg al, ah
pop ebp
ret

9 lines.

It's not quite a fair comparison since we're defining a whole
function here, as opposed to merely loading eax; my earlier
attempt, for instance, would have to be rewritten

push ebp
move ebp, esp
push edx
mov eax, dword ptr 8(ebp)
mov edx, eax
shr eax, 16
xchg eax, edx
xchg al, ah
shl eax, 16
xchg dl, dh
or eax, edx
pop edx
pop ebp
ret

14 lines.

(Your example(s) would require the 4 extra lines (push, move, pop, ret)
as well.)

You concluded: <<
I don't know if GCC is up to producing this quality of code, or not.
It would take quite some doing -- one could call it grokking
-- the subtleties of the machine architecture. >>

It'd be easier to just inline the assembly.
To time it, you could add it to something like my Kelsey.CPP
http://www.Cotse.NET/users/jeffrelf/Kelsey.CPP
http://www.Cotse.NET/users/jeffrelf/Kelsey.VCPROJ
Inline assembly is a VC-specific syntax. GCC does it differently.

But, as I keep repeating, readability is my only goal, not speed.
I say the following code is more readable,
...and it Should be legal and very optimizable... but it's neither.

uint_32 Big_First_32 ( int X ) { uint_8_P P = ( uint_8_P ) & X ;
return * P << 24 | * ++ P << 16 | * ++ P << 8 | * ++ P ; }


Optimizable? With more sequencepoints? The more sequencepoints,
the smaller the code bunches between sequencepoints that the
compiler can optimize.

--
#191, ew****@earthlink.net
It's still legal to go .sigless.
Jul 21 '05 #312
In comp.os.linux.advocacy, Olaf Baeyens
<ol**********@skyscan.be>
wrote
on Fri, 15 Apr 2005 10:33:58 +0200
<42***********************@news.skynet.be>:
btw., what's wrong with the BSWAP instruction?
And the winneerr isssss!!!!!!!!! STEFAAAAAANNNN!!!!!

He is right, since the 80486 there exist one assembler function that does
that. :-)


I knew it. :-) There just had to be a better way.

Kewl.

<snip>
The bswap instruction, available only on 80486 (yes, 486) and later
processors, converts between 32 bit little endian and big endian values.
This instruction accepts only a single 32 bit register operand. It swaps the
first byte with the fourth and the second byte with the third. The syntax
for the instruction is
bswap reg32 where reg32 is an 80486 32 bit general
purpose register.
</snip>

--
#191, ew****@earthlink.net
It's still legal to go .sigless.
Jul 21 '05 #313
In article <s5************@sirius.athghost7038suus.net>,
The Ghost In The Machine <ew***@sirius.athghost7038suus.net> wrote:
Try this code for pretty. This is in MASM/Intel syntax:

mov edx, eax ; edx=0x84838281
shr eax, 16 ; eax=0x00008483
xchg eax, edx ; edx=0x00008483,eax=0x84838281
xchg al, ah ; eax=0x84838182
shl eax, 16 ; eax=0x81820000
xchg dl, dh ; edx=0x00008384
or eax, edx ; eax=0x81828384


That usual way to do this on processors that don't specifically have an
instruction to do it is with three rotates:

ror 8, ax
ror 16, eax
ror 8, ax

The 486 and above has an instruction for this, though, so probably best
is to use that:

bswap eax
--
--Tim Smith
Jul 21 '05 #314

Hi Spooky, Re: How I think the following code is more readable,
and Should be legal and very optimizable... but it's neither: <<

uint_32 Big_First_32 ( int X ) { uint_8_P P = ( uint_8_P ) & X ;
return * P << 24 | * ++ P << 16 | * ++ P << 8 | * ++ P ; } >>

You told me: << Optimizable ? With more sequencepoints ?
The more sequencepoints, the smaller the code bunches
between sequencepoints that the compiler can optimize. >>

More Sequence_Points would be more predictible/readable,
it's absurd to not have three Sequence_Points here: a() + b() * c(),
....really Really absurd... and not so much as a warning is thrown.

Although speed is not nearly as important of an issue,
it's possible to optimize a series of Sequence_Points, of course.

Jul 21 '05 #315
"Sean Hederman" <em*******@codingsanity.blogspot.com> writes:

< snip >
Thanks. Hate giving up on a cause no matter how hopeless, but there's a
limit y'know? Used to spend ages bashing my head against a twit called
Boatwright
Eww! You let your head touch Boaty?!

How long did you have to stay in decontamination?
years ago in a non-programming forum. Feels the same. At the end
of the day I have a sore head and the nitwit is still a nitwit.


--
Tukla, Squeaker of Chew Toys
Official Mascot of Alt.Atheism
Jul 21 '05 #316
"Tukla Ratte" <tu*********@tukla.net> wrote in message
news:m2************@stitch.tukla.net...
"Sean Hederman" <em*******@codingsanity.blogspot.com> writes:

< snip >
Thanks. Hate giving up on a cause no matter how hopeless, but there's a
limit y'know? Used to spend ages bashing my head against a twit called
Boatwright


Eww! You let your head touch Boaty?!

How long did you have to stay in decontamination?


Quite some time ;D
years ago in a non-programming forum. Feels the same. At the end
of the day I have a sore head and the nitwit is still a nitwit.


--
Tukla, Squeaker of Chew Toys
Official Mascot of Alt.Atheism

Jul 21 '05 #317
I am surprised that there are still developers who say they prefer C/C++ over
C#, even, or especially, if they are writing a Windows application from
scratch. If you are developing Windows software in a competitive environment,
ignoring .NET is simply not an option. People who write their applications
with, say, C++ and STL and not C# or VB.NET must be programming for the sake
of programming itself and not to create solutions. Why would you write code
that somebody else has already written for you, tested and QA'd and nicely
integrated into the runtime? Beats me.
Jul 21 '05 #318
I'm surprised that there are still developers who say they prefer C/C++ over
C#, even, or especially, if they are writing a Windows application from
scratch. If you are developing Windows software in a competitive environment,
ignoring .NET is simply not an option. People who write their applications
with, say, C++ and STL and not C# or VB.NET must be programming for the sake
of programming itself and not to create solutions. Why would you write code
that somebody else has already written for you, tested and QA'd and nicely
integrated into the runtime? Beats me.
Jul 21 '05 #319
I'm surprised that there are still developers who say they prefer C/C++ over
C#, even, or especially, if they are writing a Windows application from
scratch. If you are developing Windows software in a competitive environment,
ignoring .NET is simply not an option. People who write their applications
with, say, C++ and STL and not C# or VB.NET must be hobbyists or are
programming for the sake of programming itself and not to create solutions.
Why would you write code that somebody else has already written for you,
tested and QA'd and nicely integrated into the runtime? Beats me.
Jul 21 '05 #320

Hi Greg_Cox, Re: CodeWright, You wrote: <<
I'm unfamiliar with a debugger by them so I can't comment. >>

You used MicroSoft's debugger then, I assume, MS_DevStudio... Right ?
( or Visual_Studio )

Visual_Studio_Net_2003 allows On_The_Fly macros,
I hit F7 to start/stop recording and then F8 to play it.
The so_called quick_Macro can then be edited, if I want,
to create a VBA script ( to assign it to a key or toolbar icon ).

Holding down the Alt and the Shift keys and then moving the text cursor
( via the mouse or keys ) allows me to select a block of text,
....instead of sequential characters.

You can assign a name to your keybindings file, I call mine Key_Bindings.VSK
Below is the .BAT file I use to save off my Visual_Studio settings.
Save_Setngs.BAT:

C:
cd "C:\Documents and Settings\Owner\Application Data\Microsoft\VisualStudio\7.1"
REM Must exit VS to save CmdUI.PRF and Key_Bindings.VSK

XCopy /Y /F 1033\CmdUI.PRF F:\VS
XCopy /Y /F Key_Bindings.VSK F:\VS
XCopy /Y /F devenv.xml F:\VS
XCopy /Y /F "C:\__\Visual Studio Projects\VSMacros71\MyMacros\__.vsmacros" F:\VS
XCopy /Y /F C:\__\X\VS.REG F:\VS
XCopy /Y /F C:\__\X\VS.VB F:\VS
XCopy /Y /F C:\__\X\Save_Setngs.BAT F:\VS
XCopy /Y /F C:\__\X\Restore_Setngs.BAT F:\VS
XCopy /Y /F C:\__\X\Bit_Stream.TTF F:\VS

Pause

REM More info at:
REM http://blogs.msdn.com/jledgard/archi.../05/67869.aspx

Below is how I restore them to another machine, when I have the privileges.
Restore_Setngs.BAT:

XCopy /Y /F CmdUI.PRF "C:\Documents and Settings\BLab-242\Application Data\Microsoft\VisualStudio\7.1\1033"

REM Key_Bindings must be selected by hand.

XCopy /Y /F "Key_Bindings.VSK" "C:\Documents and Settings\BLab-242\Application Data\Microsoft\VisualStudio\7.1"
XCopy /Y /F devenv.xml "C:\Documents and Settings\BLab-242\Application Data\Microsoft\VisualStudio\7.1"
XCopy /Y /F __.vsmacros "C:\__\Visual Studio Projects\VSMacros71\MyMacros\__.vsmacros"
rem XCopy /Y /F __.vsmacros "C:\Documents and Settings\blab-242\My Documents\Visual Studio Projects\VSMacros71\MyMacros\__.vsmacros"
VS.REG

Pause

Nov 22 '05 #321
In article <Je************************@Cotse.NET>, Me@Privacy.NET
says...

Hi Greg_Cox, Re: CodeWright, You wrote: <<
I'm unfamiliar with a debugger by them so I can't comment. >>

You used MicroSoft's debugger then, I assume, MS_DevStudio... Right ?
( or Visual_Studio )
Correct, except when we had to debug Windows itself, then we used the
kernel debugger. While we were developing Exchange Server we were also
taking weekly drops of what would become Win2k Server from the Windows
dev team. I NEVER want to go through that again. What a nightmare...

Visual_Studio_Net_2003 allows On_The_Fly macros,
I hit F7 to start/stop recording and then F8 to play it.
The so_called quick_Macro can then be edited, if I want,
to create a VBA script ( to assign it to a key or toolbar icon ).

Holding down the Alt and the Shift keys and then moving the text cursor
( via the mouse or keys ) allows me to select a block of text,
...instead of sequential characters.


I'll have to remember both of those. Thanks.

--
"There are 10 kinds of people in the world:
those that understand binary and those that don't." - Unknown
Nov 22 '05 #322

Hi Olaf_Baeyens ( and Greg_Cox ),

It remains to be seen whether Visual_Studio itself, for example,
would ever run under the Dot_Net_Program.

Further, even if that happened,
it remains to be seen if it would become a success or not.
Coders could always use a debugger written in C instead.

Imagine a debugger running under the Dot_Net_Program ! ?

Remember, Dot_Net is an untested pig which forbids #define.
C goes back to 1970... Firefox is written in C++, Linux in C.

Nov 22 '05 #323

Hi Greg_Cox, Re: VS's block_select and quick_macros, You told me: <<
I'll have to remember both of those. Thanks. >>

You're welcome, of course.
I had been wondering for a long time what debugger MicroSoft-proper used.
I'm very glad to hear it was Visual_Studio.

Nov 22 '05 #324

Hi Greg_Cox ( and Olaf_Baeyens ),

I used MS_C_6 for years, I'm using only MS_CPP_7_1 right now,
Visual_Studio_Net_2003... but I have no plans to use managed code.

I switched to C++ from C so that I could declare variables
without braces, {}, and do & referencing, instead of pointers.
For example: { func(); int Y, & X = Y ; func(); }

I just like the way it looked and porting my code was no big deal.

The C99 specs allows that stuff, but MicroSoft's C doesn't.

Nevertheless, C++'s String, cout and the STL have never appealed to me.
I like to keep a closer eye on allocations/deallocations,
and I have my own way of handling dynamic arrays.

Nov 22 '05 #325

Hi Ernestine, Ya wrote: << I wish I knew what ya all were talkin' 'bout,
Precedence ain't got not'n to do with what beer I drink. >>

When coding, it helps to know the order of execution,
Spooky apparently has no clue about that.

Unable to recognize a simple coder, he also has no clue about who I am.

Nov 22 '05 #326
In comp.os.linux.advocacy, Jeff_Relf
<Me@Privacy.NET>
wrote
on 12 Apr 2005 07:24:44 GMT
<Je************************@Cotse.NET>:

Hi Ernestine, Ya wrote: << I wish I knew what ya all were talkin' 'bout,
Precedence ain't got not'n to do with what beer I drink. >>

When coding, it helps to know the order of execution,
Spooky apparently has no clue about that.
I have more than a clue than you might think.

The HP PA Risc architecture, for instance (a Unix
workstation running HP/UX at one point which I had the
privilege of using for some years in my prior job --
nice machine, actually), had some very interesting ideas
of exactly when to execute an instruction, for example.
Basically, the processor had the option (and usually took
it) of executing the instruction following a conditional
branch, even though the branch was taken.

This presumably gave compiler optimizers fits.

http://h21007.www2.hp.com/dspp/tech/tech_TechDocumentDetailPage_IDX/1,1701,958!33!250,00.html

<excerpt>

pa-risc 1.1 architecture and instruction set reference manual
[...]
concept of delayed branching

All branch instructions exhibit the delayed branch
feature. This implies that the major effect of the branch
instruction, the actual transfer of control, occurs one
instruction after the execution of the branch. As a result,
the instruction following the branch (located in the delay
slot of the branch instruction) is executed before control
passes to the branch destination. The concept of delayed
branching is illustrated in Figure 42.

Execution of the delay slot instruction, however, may be
skipped ("nullified") by setting the "nullify" bit in the
branch instruction to 1.

delayed branching
program segment
Location Instruction Comment
100 STW r3, 0(r6) ; non-branch instruction
104 BLR r8, r0 ; branch to location 200
108 ADD r7, r2, r3 ; instruction in delay slot
10C OR r6, r5, r9 ; next instruction in linear code
; sequence
.. .
.. .
.. .
200 LDW 0(r3), r4 ; target of branch instruction

execution sequence
Location Instruction Comment
100 STW r3, 0(r6) ;
104 BLR r8, r0 ;
108 ADD r7, r2, r3 ; delay slot
; instruction is executed before
200 LDW 0(r3), r4 ; execution of
; target instruction

</excerpt>

Also, the compiler, when presented with your example (paraphrased):

int swap32(int v)
{
unsigned char * p = (unsigned char *) &v;
p += 4;
return (*--p << 24)|(*--p << 16)|(*--p << 8)|(*--p);
}

has the option of evaluating the expression either
left-to-right or right-to-left, at the whim of the compiler
designer(s). (Unless Kelsey tells me different -- he's more
familiar with the C/C++ specifications than I am. :-))

However, some of the best optimization is done within
the compiler by reading the code *backwards* -- e.g., the
compiler might forbear a final store for a local variable
to save time, as the variable will just be discarded
later. In fact, the better compilers don't bother with
storing local variables at all, if they don't need to and
sufficient registers are available. There are a number of
other possibilities, some of which I've already alluded to.

I'm also familiar with some of the problems facing optimizers.
Briefly put, the code

int * selectAPointer(int * ap, int * bp, int * cp);

int doSomething()
{
int a = 1, b=2, c=3, *p;
int d1 = a+b+c;
p = selectAPointer(&a,&b,&c);
*p ++;
int d2 = a+b+c;
}

would have to be very carefully handled, as p might very
well point to a, b, or c after selectAPointer() returns,
or it might point to somewhere compiletely different -- but
there's no way for the compiler to tell here. Therefore,
both d1 and d2 will probably have to be explicitly coded as
something along the lines of:

MOV a(SP), r1
ADD b(SP), r1
ADD c(SP), r1
MOV r1, d1(SP)

Without the selectAPointer() call, the compiler has
the option of *merging* d1 and d2, conceptually (using
a method called "common subexpression elimination"), and
potentially making the code more efficient -- if only
by 4 instructions and a now-redundant stackframe location.

It might also remove the last instruction, and keep
d1 in a register for the length of the code.

I bring all this up to illustrate that your pattern of
linear thinking, generally desirable though it is, has
some drawbacks.

Be clear in your coding now, and your coding will be
clear to you later, when you reread it. :-) It will
also be clear to the compiler, when *it* reads it.

Of course, knowing the way you code, the code may very
well be clear to you already; just don't expect it to
make sense to the rest of us, without careful analysis.
The ideal, at least to a manager's thinking, is to shuffle
people around at need between projects, both to keep them
interested and to maximize utilization of resource --
this may require reading and modifying someone else's code.

There is at least one hacker [according to Stephen Levy,
anyway] out there who writes extremely ingenious -- most
would say incomprehensible -- code with nary a comment.
I would subscribe to that notion myself, except that
most machine code is pretty much as one might see from
the foregoing: without the comments, one might as well be
looking at gobbledygook, although the machine "understands"
it perfectly well as long as it knows which registers to
modify and which memory locations to wiggle. PA Risc is
slightly unusual in its "delay slot", but is otherwise
more or less typical regarding machines, though it has
more registers (32 at the user level; I can't say I played
with the space registers all that much) than one's typical
Intel hardware, and is probably better designed from an
instruction standpoint, since it didn't have to worry about
8080 source code compatibility. And even then, the above
is *assembly*; the actual machine code would be little more
than a bunch of hex numbers or charge packets.

It was once common for system programmers to pore over
pages of printouts dumped from a console in old IBM
hardware, for example (fortunately, that was before
my time). Of course, that was also when an IBM machine
had all of maybe 8K or 16K of RAM.

I've also caught MS VC++ (version 5.0) in a bona fide
memory corruption condition. I'll admit I'm not sure who
created the bug (as it was running on NT3.5 or NT4, whose
memory allocation was slightly suspect) but the assembly
listing from a section of code I was working on at the
time was quite corrupted for the space of about 10 lines.
As Ronald Reagan once said, "trust but verify".

However, compiler mangling is not the first thing that
comes to mind when one's code does the goofy, though --
most likely, it's one's code.

Unable to recognize a simple coder, he also has no clue about who I am.


There are more things in Heaven and Earth, Horatio, than are dreamt of
in your philosophies.
-- Hamlet, Act I, Scene 5

--
#191, ew****@earthlink.net
It's still legal to go .sigless.
Nov 22 '05 #327

Hi Kelsey_Bjarnason ( and Gerry ),

Re: This Swap_32_x86() working for gcc but not for MS_CPP_7_1:

typedef unsigned char * uint_8_P ;

int Swap_32_x86 ( int X ) { uint_8_P P = ( uint_8_P ) & X ;
return * P << 24 | * ++ P << 16 | * ++ P << 8 | * ++ P ; }
main() {
// prints 0x84848484 ! ! MS_CPP_7_1 BUG
printf( "%x", Swap_32_x86( 0x84838281 ) ); }

You claimed there's, << undefined behavior as a result of
the multiple modifications involved between sequence points,
from which the associativity provides no protection at all. >>

I don't know what you might be asserting here, if anything,
but I hope you have a lot of credible documents to support you.

MS_CPP_7_1's precedence is well defined.

MicroSoft claims that the | operator is evaluated left to right:
http://msdn.microsoft.com/library/de....operators.asp

Operator |
Name Bitwise inclusive OR
Associativity Left to right

Note that this works:

typedef unsigned char * uint_8_P ; int _1, _2, _3, _4 ;

int Swap_32_x86_NoBug ( int X ) { uint_8_P P = ( uint_8_P ) & X ;
return ( _1 = * P << 24 ) | ( _2 = * ++ P << 16 )
| ( _3 = * ++ P << 8 ) | ( _4 = * ++ P ); }

main() {
// prints 0x81828384 as it should.
printf( "%x", Swap_32_x86_NoBug( 0x84838281 ) ); }

Swap_32_x86() should work like this ( but doesn't ):
return * P << 24 | * ++ P << 16 | * ++ P << 8 | * ++ P ; }
1. * P -> Reg
2. Reg << 24 -> Reg
3. ++ P -> Reg2
4. * Reg2 -> Reg2
5. Reg2 << 16 -> Reg2
6. Reg | Reg2 -> Reg
7. ++ P -> Reg2
8. * Reg2 -> Reg2
9. Reg2 << 8 -> Reg2
10. Reg | Reg2 -> Reg
11. ++ P -> Reg2
12. * Reg2 -> Reg2
13. Reg | Reg2 -> Reg
14. Return Reg.

Nov 22 '05 #328
In article <Je************************@Cotse.NET>,
Jeff_Relf <Me@Privacy.NET> wrote:
[unreadable crap...I'll try to salvage what I can from his poor layout]

The code in question:
int Swap_32_x86 ( int X ) { uint_8_P P = ( uint_8_P ) & X ;
return * P << 24 | * ++ P << 16 | * ++ P << 8 | * ++ P ; }
Why it doesn't work:
undefined behavior as a result of
the multiple modifications involved between sequence points, from
which the associativity provides no protection at all. >>


Relf is not convinced: I don't know what you might be asserting here, if anything,
but I hope you have a lot of credible documents to support you.


Read this:

<http://msdn.microsoft.com/library/de.../en-us/vclang/
html/_clang_c_sequence_points.asp>

In C and C++, precedence and associativity basically determine the shape
of the parse tree. They do *NOT* determine the order of evaluation of
things, other than indirectly (in that an operation can not be done
until the value of both operands is known).

For example, consider a()+b()*c(). The compile can call those three
functions in any order it wants. It will have to then do the
multiplication before it does the addition.

--
--Tim Smith
Nov 22 '05 #329
Tim Smith wrote:
For example, consider a()+b()*c(). The compile can call those three
functions in any order it wants. It will have to then do the
multiplication before it does the addition.


What if a static global is set in a() that needs to be called in b(),
c() to get a correct calculation?
Nov 22 '05 #330

Jeff_Relf wrote:
return * P << 24 | * ++ P << 16 | * ++ P << 8 | * ++ P ;

}

1. &&,|| : Are short circuited
: have sequence points between operands
&,| : Are NOT short circuited
: DO NOT have sequence points between operands
2. From the ANSI/ISO C Standard 9899-1990,
section 6.3 "Expressions", paragraph 2:
"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."
3. Modifying a value more than once between sequence points is
undefined.
4. A compiler can do ANYTHING IT WANTS when behavior is undefined
5. You modify P more than once between sequence points
6. This is NOT a compiler bug
This is programmer error

Information on these topocs is easily available from GOOGLE

Hope this helps
Bill

Nov 22 '05 #331
Tim Wrote:
In C and C++, precedence and associativity basically determine the shapeof the parse tree. They do *NOT* determine the order of evaluation of things, other than indirectly (in that an operation can not be done
until the value of both operands is known).


In the case of (&&, ||) the order of operation IS defined as left to
right and STOPS once the outcome is known (this is called short
circuiting)
SO for example

if ( (F(x) < 0) || (G(x) <0) )
Blah();

F(x) will be executed first.
If (F(x) < 0) is true we NEVER execute the second test

Thus G(x) is not guaranteed to run.

-----------------------------------
Unfortunately for Refl, he didn't use these operators
He used the bitwise operators and they DON'T short circuit

Had he used the boolean operators his code MIGHT have worked.
Or at the least it would have defined behavior.

Hope this helps
Bill

Nov 22 '05 #332

Howdy there Bill, Re: * ++ P << 16 | * ++ P << 8...,

That code Should work. Why... you ask ?
Because it's much more readable than this: P [ 1 ] << 16 | P [ 2 ] << 8
So it's a bug in both MS_CPP_7_1 and ISO_C.

Hope that helps.

P.S. This iterates MS_CPP's sequence points:
http://msdn.microsoft.com/library/de...nce_points.asp

Nov 22 '05 #333
Relf Wrote:
Howdy there Bill, Re: * ++ P << 16 | * ++ P << 8..., That code Should work. Why... you ask ?
Because it's much more readable than this: P [ 1 ] << 16 | P [ 2 ] << 8

Huh????
What does supposed READABILITY have to do with Code Correctness or
Undefined Behavior???
So it's a bug in both MS_CPP_7_1 and ISO_C.
That does not logically follow

....
P.S. This iterates MS_CPP's sequence points:
http://msdn.microsoft.com/library/default.asp?url=/library/en->us/vclang98/html/_pluslang_c.2b2b_.sequence_points.asp


I carefully looked over the list of sequence points and don't see one
that applies to your case
Which one do YOU think applies?

Bill

Nov 22 '05 #334
In article <42**************@speakeasy.net>, Hurray for Peter Pumpkinhead wrote:
For example, consider a()+b()*c(). The compile can call those three
functions in any order it wants. It will have to then do the
multiplication before it does the addition.


What if a static global is set in a() that needs to be called in b(),
c() to get a correct calculation?


Then you have to write it like this:

int temp = a();
whatever = temp + b()*c();

--
--Tim Smith
Nov 22 '05 #335
In comp.os.linux.advocacy, Hurray for Peter Pumpkinhead
<ja************@speakeasy.net>
wrote
on Wed, 13 Apr 2005 07:12:37 -0700
<42**************@speakeasy.net>:
Tim Smith wrote:
For example, consider a()+b()*c(). The compile can call those three
functions in any order it wants. It will have to then do the
multiplication before it does the addition.


What if a static global is set in a() that needs to be called in b(),
c() to get a correct calculation?


Then one has unpredictable behavior and will be lucky to
get a result even remotely reproducible, and probably one
will get some rather subtle and oddball symptoms to hash
through before one gets at the root cause of the problem,
during porting of the application from a platform that
works to another platform essential to one's business plan.

In short: problem-in-waiting. :-)

Of course the workaround isn't too bad; either factor out
the global and have a setup() routine prior to evaluating
the expression in question, or put the result of a()
into a variable, and force the issue:

double aVal = a();
/* ... use ... */ aVal+b()*c(); /* ... */

I could see all of a(), b() and c() calling a setup()
routine if they all needed access to the same pointer
(setup() would create and/or return it to them), though;
so long as setup() does the same thing every time it won't
really matter *who* gets called first:

***

Something * staticValue;

void setup()
{
/* ... blah blah whatever blah blah ... */
staticValue = new Something(...);
/* ... blah blah whatever blah blah ... */
}

double a()
{
if(staticValue == 0) setup();
return staticValue->a();
}

double b()
{
if(staticValue == 0) setup();
return staticValue->b();
}

double c()
{
if(staticValue == 0) setup();
return staticValue->c();
}

***

This is admittedly not the best of code (thread problem?
*What* thread problem? :-) ) but at least it wouldn't depend
on an explicit order of evaluation.

--
#191, ew****@earthlink.net
It's still legal to go .sigless.
Nov 22 '05 #336
In comp.os.linux.advocacy, Bill
<sa********@hotmail.com>
wrote
on 13 Apr 2005 08:15:13 -0700
<11**********************@l41g2000cwc.googlegroups .com>:
Relf Wrote:
Howdy there Bill, Re: * ++ P << 16 | * ++ P << 8...,
That code Should work. Why... you ask ?
Because it's much more readable than this: P [ 1 ] << 16 | P [ 2 ]

<< 8

Huh????
What does supposed READABILITY have to do with Code Correctness or
Undefined Behavior???


Ah, remember -- it's the "Jeff-Relf-Readability Test". If he can
read it, no problem. If he can't, it's all your fault. :-)
So it's a bug in both MS_CPP_7_1 and ISO_C.
That does not logically follow


Make that "Jeff-Relf-Logic" as well.

...
P.S. This iterates MS_CPP's sequence points:
[URL repair]
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang98/html/_pluslang_c.2b2b_.sequence_points.asp
I carefully looked over the list of sequence points and don't see one
that applies to your case
Which one do YOU think applies?


Interesting -- "An expression can modify an objects [sic] value only
once between consecutive sequence points". I think this explains
the behavior in part that he saw earlier, in that the declaration

unsigned char * P = (unsigned char *) &X + 4;
return *--P << 24 | *--P << 16 | *--P << 8 | *--P;

was for some reason returning 0x20202020 for input value 0x00000020;
apparently the four decrements were being collapsed.

However, that does not explain why the modified form

unsigned char * P = (unsigned char *) &X;
return *P++ << 24 | *P++ << 16 | *P++ << 8 | *P;

actually *works*.

My brain is starting to hurt.

Bill


--
#191, ew****@earthlink.net
It's still legal to go .sigless.
Nov 22 '05 #337

Hi Spooky, I'm saying that the following could should work, but doesn't:

Large_is_First_32 ( int X ) {
unsigned char * P = ( unsigned char * ) & X ;
return * P ++ << 24 | * P ++ << 16 | * P ++ << 8 | * P ; }

C_99 and MS_CPP should both be updated so that it will work, in my opinion,
because P [ 1 ] << 16 | P [ 2 ] << 8
is too ugly, too weird, and too unnecessary.

This is the code that works:

#include <StdLib.H>
typedef char * int_8_P ; typedef unsigned char * uint_8_P ; int rv ;

int Large_is_First_32 ( int X ) {
uint_8_P P = ( uint_8_P ) & X ;
return * P << 24 | P [ 1 ] << 16 | P [ 2 ] << 8 | P [ 3 ] ; }

int main(){ int_8_P P = "84838281" ;
int X = strtoul( P, & P, 16 ); rv = Large_is_First_32( X );
return rv ; } // rv is now 0x81828384

The optimizer inlines the code as follows:
rv = * P << 24 | P [ 1 ] << 16 | P [ 2 ] << 8 | P [ 3 ] ;

1D xor ecx,ecx
1F mov ch,al
21 movzx edx,ah
24 mov dword ptr [ esp + 0Ch ],eax
28 shr eax,10h
2B or ecx,edx
2D movzx edx,al
30 shl ecx,8
33 or ecx,edx
35 movzx eax,ah
38 shl ecx,8
3B or eax,ecx
3D mov dword ptr [ rv ( 403018h ) ],eax

Such fast and pretty code !

The strtoul() must be there or my code gets optimized away.
rv, a global, must be there to confirm that it works.

Nov 22 '05 #338
In comp.os.linux.advocacy, Jeff_Relf
<Me@Privacy.NET>
wrote
on 14 Apr 2005 08:05:26 GMT
<Je************************@Cotse.NET>:

Hi Spooky, I'm saying that the following could should work, but doesn't:

Large_is_First_32 ( int X ) {
unsigned char * P = ( unsigned char * ) & X ;
return * P ++ << 24 | * P ++ << 16 | * P ++ << 8 | * P ; }

C_99 and MS_CPP should both be updated so that it will work, in my opinion,
because P [ 1 ] << 16 | P [ 2 ] << 8
For GCC/x86 and X = 0x84838281,

return * P ++ << 24 | * P ++ << 16 | * P ++ << 8 | * P ; }

returns 0x81818181.

Looks like GCC has a "bug" as well.

An alternative formulation:

return * P << 24 | * ++ P << 16 | * ++ P << 8 | * ++ P ; }

does work correctly in GCC.
is too ugly, too weird, and too unnecessary.

This is the code that works:

#include <StdLib.H>
typedef char * int_8_P ; typedef unsigned char * uint_8_P ; int rv ;

int Large_is_First_32 ( int X ) {
uint_8_P P = ( uint_8_P ) & X ;
return * P << 24 | P [ 1 ] << 16 | P [ 2 ] << 8 | P [ 3 ] ; }

int main(){ int_8_P P = "84838281" ;
int X = strtoul( P, & P, 16 ); rv = Large_is_First_32( X );
return rv ; } // rv is now 0x81828384

The optimizer inlines the code as follows:
rv = * P << 24 | P [ 1 ] << 16 | P [ 2 ] << 8 | P [ 3 ] ;

1D xor ecx,ecx
1F mov ch,al
21 movzx edx,ah
24 mov dword ptr [ esp + 0Ch ],eax
28 shr eax,10h
2B or ecx,edx
2D movzx edx,al
30 shl ecx,8
33 or ecx,edx
35 movzx eax,ah
38 shl ecx,8
3B or eax,ecx
3D mov dword ptr [ rv ( 403018h ) ],eax

Such fast and pretty code !
Feh.

Try this code for pretty. This is in MASM/Intel syntax:

mov edx, eax ; edx=0x84838281
shr eax, 16 ; eax=0x00008483
xchg eax, edx ; edx=0x00008483,eax=0x84838281
xchg al, ah ; eax=0x84838182
shl eax, 16 ; eax=0x81820000
xchg dl, dh ; edx=0x00008384
or eax, edx ; eax=0x81828384

There's probably better methods but I've already reduced it to 7
instruction lines by simply coding it by hand. Works like a champ.

I could reduce it to 3 if there's a method to exchange
the 16-bit register ax with the high 32-bits of eax.
However, the obvious choices 'xchg eax,ax' and 'xchg eah,ax'
both fell flat.

(I don't know if GCC is up to producing this quality of code,
or not. It would take quite some doing -- one could call it
"grokking" -- the subtleties of the machine architecture.)

The strtoul() must be there or my code gets optimized away.
rv, a global, must be there to confirm that it works.


--
#191, ew****@earthlink.net
It's still legal to go .sigless.
Nov 22 '05 #339

Hi Spooky, Re: Your mod of the code I showed, You told me: <<
return * P << 24 | * ++ P << 16 | * ++ P << 8 | * ++ P ; }
does work correctly in GCC. >>

But that's a quirk, of course.
The solution would be to modify the MS_CPP and gcc compilers themselves,
as well as the C_2006 standard, to introduce Many more sequence points.

For example,
Each of the following should have it's left_to_right'ness guaranteed,
complete with so_called sequence_points in the obvious places:
1. char Buffer [] = { func(), /* Seq_Pnt */ func(), /* Seq_Pnt */ func() };
2. func( func(), /* Seq_Pnt */ func(), /* Seq_Pnt */ func() );
3. return * ++ P << 16 | /* Seq_Pnt */ * ++ P << 8 ;

At the very Very least, a compiler warning should be thrown !

Re: How I liked the disassembly of the working C++ code I showed,

You replied: << Feh. Try this code for pretty.
This is in MASM/Intel syntax:

mov edx, eax ; edx=0x84838281
shr eax, 16 ; eax=0x00008483
xchg eax, edx ; edx=0x00008483,eax=0x84838281
xchg al, ah ; eax=0x84838182
shl eax, 16 ; eax=0x81820000
xchg dl, dh ; edx=0x00008384
or eax, edx ; eax=0x81828384

There's probably better methods but I've already reduced it to 7
instruction lines by simply coding it by hand. Works like a champ. >>

Wow, I'm impressed ! So much for my claim that you don't do assembly anymore.

You added: << I could reduce it to 3 if there's a method to exchange
the 16-bit register ax with the high 32-bits of eax. However,
the obvious choices xchg eax,ax and xchg eah,ax both fell flat. >>

Wow again, You just taught me some x86 assembly:
1. ax is a short.
2. al is ax's low byte.
3. ah is ax's high byte.
4. eax is a long.

Olaf taught me that this is moving an int off the stack to ecx

mov ecx, dword ptr [ esp + 18h ]

You concluded: <<
I don't know if GCC is up to producing this quality of code, or not.
It would take quite some doing -- one could call it grokking
-- the subtleties of the machine architecture. >>

It'd be easier to just inline the assembly.
To time it, you could add it to something like my Kelsey.CPP
http://www.Cotse.NET/users/jeffrelf/Kelsey.CPP
http://www.Cotse.NET/users/jeffrelf/Kelsey.VCPROJ

But, as I keep repeating, readability is my only goal, not speed.
I say the following code is more readable,
....and it Should be legal and very optimizable... but it's neither.

uint_32 Big_First_32 ( int X ) { uint_8_P P = ( uint_8_P ) & X ;
return * P << 24 | * ++ P << 16 | * ++ P << 8 | * ++ P ; }

Nov 22 '05 #340
> Feh.

Try this code for pretty. This is in MASM/Intel syntax:

mov edx, eax ; edx=0x84838281
shr eax, 16 ; eax=0x00008483
xchg eax, edx ; edx=0x00008483,eax=0x84838281
xchg al, ah ; eax=0x84838182
shl eax, 16 ; eax=0x81820000
xchg dl, dh ; edx=0x00008384
or eax, edx ; eax=0x81828384

There's probably better methods but I've already reduced it to 7
instruction lines by simply coding it by hand. Works like a champ.

I could reduce it to 3 if there's a method to exchange
the 16-bit register ax with the high 32-bits of eax.
However, the obvious choices 'xchg eax,ax' and 'xchg eah,ax'
both fell flat.

Very nice. :-)

But the big question now in modern processors is yours faster?
I do know that some simple instructions that are used more often tends to be
faster than instructions that might have one opcode but not used that much.
And another thing is that that modern processors execute stuff out of order.
So less instructions does not mean necesarely faster performance, but it
could and in your solution it might.

The only way to determin what is faster is to actually measure it.
And then again, it might be processor dependend.
Nov 22 '05 #341
> return * P << 24 | * ++ P << 16 | * ++ P << 8 | * ++ P ; }
does work correctly in GCC. >>

But that's a quirk, of course.
Yes it shoud have worked in my opinion too.
But this is life, nothing is perfect.

I also discovered one time that if you use events in a C++ class VC++ 2002
then you get an access violation if the class happens not to have a
constructor defined and implemented in the header file.
So for week I struggled with that event thing, and funny enough the examples
worked, but mine failed. Then I started to realize looking at the assmbly
code that the variables of those events didn't get initialized. Clearly a
bug in the C++ compiler. Now my code works fine, since I now put a complete
constructor in the headre file. So the code generated is now correct.
At the very Very least, a compiler warning should be thrown !
I fully agree.
Wow, I'm impressed ! So much for my claim that you don't do assembly anymore. In my case it is 15 years old knowledge. I only use it to look at the
generated code to find bugs in my code and to optimize my functions to speed
up without resorting to assembler.
Or to learn a new language, because I can compare it to something I already
know.

And now I do this with IL assembler generated by .NET. One thing I discover
is that properties are not optimized, not inlined so that could explain why
some C# code could be slower. But then again if I look at my C++ code of the
VC++ 2003 Standard, none of my properties gets inlined too. And this
explains why my C++ code and C# code are almost the same speed on the same
computer and the same OS and compiled with the same compiler environment. I
hope that The VS 2005 gets a better optimizer for that.

You added: << I could reduce it to 3 if there's a method to exchange
the 16-bit register ax with the high 32-bits of eax. However,
the obvious choices xchg eax,ax and xchg eah,ax both fell flat. >>

Wow again, You just taught me some x86 assembly:
1. ax is a short.
2. al is ax's low byte.
3. ah is ax's high byte.
4. eax is a long.
In the case of Intel like processors, the ax, eax register gets specialized
for processing things.It is another name for accumulator.
You will discover that any operation is done on that register, so a lot of
code is copying registers to the eax register and then move it back.

Another thing to know is that you cannot access the upper word part of eax.
(or the ebx, ecx, edx)
Only the lower word part that could be split into a high byte and a low
byte.

eax is the 32 bit register
ax is the same as LOWORD(eax)
and al would be like LOBYTE(ax)
and ah would be like HIBYTE(ax)

So to get the HIWORD(eax), you must >> 16 to it ends into the ax part.
Then you can access it.

Typically eax is used for calculating things.
ebx is used as index pointer
ecx is typically used as counter
edx is typically used as destination index pointer.
But in the case of an optimizer compiler you might lose that relationship.

Another thing somethin like this "xor ecx,ecx" is actually saying set
ecx to null.
This notation is only one byte and superfast compared to loading it with a
actual value.

And the reason why the P++ and P-- tends to be faster in C++ is because it
translates to an assembler instruction
inc ebx // P++
dec ebx // P--

While the P=P+1 would probably translate to somthing like this (just
guessing)
//P++
mov eax,ebx
mov ebx,1
add eax,ebx

//P--
mov eax,ebx
mov ebx,1
sub eax,ebx
Olaf taught me that this is moving an int off the stack to ecx

mov ecx, dword ptr [ esp + 18h ]

Yes a local variable located at 18h positions from your return address. :-)
And if you get something like this "mov ecx, dword ptr [ esp - 18h ]"
then it is some parameter passed on from outside your function.

Nov 22 '05 #342
Jeff_Relf wrote:
uint_32 Big_First_32 ( int X ) { uint_8_P P = ( uint_8_P ) & X ;
return * P << 24 | * ++ P << 16 | * ++ P << 8 | * ++ P ; }


I thought it was pretty cool that Ghost basically doused your code with
some shit that was totally Elegant and that makes Ghost a Mogul and you
a Serf.

Prolly if he took the time to read your 'c' code...well less just say
the Machine Got Gaaaame.
Nov 22 '05 #343
Olaf Baeyens wrote:
Feh.

Try this code for pretty. This is in MASM/Intel syntax:

mov edx, eax ; edx=0x84838281
shr eax, 16 ; eax=0x00008483
xchg eax, edx ; edx=0x00008483,eax=0x84838281
xchg al, ah ; eax=0x84838182
shl eax, 16 ; eax=0x81820000
xchg dl, dh ; edx=0x00008384
or eax, edx ; eax=0x81828384

There's probably better methods but I've already reduced it to 7
instruction lines by simply coding it by hand. Works like a champ.

I could reduce it to 3 if there's a method to exchange
the 16-bit register ax with the high 32-bits of eax.
However, the obvious choices 'xchg eax,ax' and 'xchg eah,ax'
both fell flat.


Very nice. :-)

But the big question now in modern processors is yours faster?
I do know that some simple instructions that are used more often tends to be
faster than instructions that might have one opcode but not used that much.
And another thing is that that modern processors execute stuff out of order.
So less instructions does not mean necesarely faster performance, but it
could and in your solution it might.

The only way to determin what is faster is to actually measure it.
And then again, it might be processor dependend.


btw., what's wrong with the BSWAP instruction?

Stefan
Nov 22 '05 #344
> btw., what's wrong with the BSWAP instruction?

And the winneerr isssss!!!!!!!!! STEFAAAAAANNNN!!!!!

He is right, since the 80486 there exist one assembler function that does
that. :-)

<snip>
The bswap instruction, available only on 80486 (yes, 486) and later
processors, converts between 32 bit little endian and big endian values.
This instruction accepts only a single 32 bit register operand. It swaps the
first byte with the fourth and the second byte with the third. The syntax
for the instruction is
bswap reg32where reg32 is an 80486 32 bit general purpose register.
</snip>
Nov 22 '05 #345
This does the trick in VC++ 2003

int iswapped=0;
int iOriginal=0x01234567;
__asm {
mov eax,iOriginal
bswap eax
mov iswapped,eax
}

Which translates to:

mov dword ptr [iswapped],0 // int iswapped=0;
mov dword ptr [iOriginal],1234567h // int iOriginal=0x01234567;
// and now the __asm part
mov eax,dword ptr [iOriginal] // mov eax,iOriginal
bswap eax
mov dword ptr [iswapped],eax // mov iswapped,eax

And in a optimizer compiler: "mov eax,dword ptr [iOriginal]" and "mov dword
ptr [iswapped],eax" might have been stripped away since the variables would
probaly already exist in eax.

So for those that thought that Assembler died, it is still there, absorbed
into the C++ language.
Nov 22 '05 #346

Hi Stefan, You ased: << what's wrong with the BSWAP instruction ? >>

Variations of my Big_First_32() illustrate serious problems
with MS_CPP, not just with Sequence_Points,
but, even more seriously, with how it's /Og switch, Global optimizations,
breaks perfectly legal code.

Spooky would say that BSWAP doesn't work on the PowerPC, or something.

MS_CPP has _byteswap_ulong() which is just a BSWAP instruction:

mov ecx,eax
bswap ecx

I have a cheap_ass Celeron with only a 128 KB L2 cache.
After double_clicking Kelsey.EXE three times in a row, for good measure,
these are the times that I'm getting:
.00445 Seconds, Sum 2147244176424960, _byteswap_ulong( 0 - 999,999 ).
.00608 Seconds, Sum 2147244176424960, Swap_32( 0 - 999,999 ).
.00593 Seconds, Sum 2147244176424960, Big_First_32( 0 - 999,999 ).
.01049 Seconds, Sum 2147244176424960, htonl( 0 - 999,999 ).

http://www.Cotse.NET/users/jeffrelf/Kelsey.EXE
http://www.Cotse.NET/users/jeffrelf/Kelsey.CPP
http://www.Cotse.NET/users/jeffrelf/Kelsey.VCPROJ

#pragma warning( disable: 4244 )
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <StdLib.H>
#include <stdio.h>
#include <IO.H>
#include <Winsock2.H>
#pragma comment( lib, "Ws2_32.LIB")

#define Loop( N ) int J = - 1, LLL = N ; while ( ++ J < LLL )
#define Tics ( QueryPerformanceCounter( ( Quad * ) & _Tics ), _Tics )
#define Secs ( _Secs = Tics / Secnd_Dub )

typedef char * int_8_P ;
typedef unsigned char uint_8 ; typedef uint_8 * uint_8_P ;
typedef unsigned __int32 uint_32 ;
typedef LARGE_INTEGER Quad ;

double Secnd_Dub, _Secs, Mark ; __int64 _Tics, Secnd ;

uint_32 Big_First_32 ( int & X ) { uint_8_P B = ( uint_8_P ) & X ;
return * B << 24 | B [ 1 ] << 16 | B [ 2 ] << 8 | B [ 3 ]; }

uint_32 Swap_32 ( int X ) {
return uint_8( X ) << 24 | uint_8( X >> 8 ) << 16
| uint_8( X >> 16 ) << 8 | uint_8( X >> 24 ); }

main() {
QueryPerformanceFrequency( ( Quad * ) & Secnd ); Secnd_Dub = Secnd ;
FILE * fp = fopen( "AA.TXT", "w" );
const int Times = 1000 * 1000 ;

__int64 X = 0 ; Mark = Secs ;
{ Loop( Times ) X += _byteswap_ulong( J ); } double Dur = Secs - Mark ;

__int64 X2 = 0 ; Mark = Secs ;
{ Loop( Times ) X2 += Swap_32( J ); } double Dur2 = Secs - Mark ;

__int64 X3 = 0 ; Mark = Secs ;
{ Loop( Times ) X3 += Big_First_32( J ); } double Dur3 = Secs - Mark ;

__int64 X4 = 0 ; Mark = Secs ;
Loop( Times ) X4 += htonl( J ); double Dur4 = Secs - Mark ;

char SecStr [ 99 ] ;
sprintf( SecStr, "%1.5f" , Dur );
fprintf( fp, "%s Seconds, Sum %I64d, _byteswap_ulong( 0 - 999,999 ).\n"
, SecStr + ( * SecStr == '0' ), X );

sprintf( SecStr, "%1.5f" , Dur2 );
fprintf( fp, "%s Seconds, Sum %I64d, Swap_32( 0 - 999,999 ).\n"
, SecStr + ( * SecStr == '0' ), X2 );

sprintf( SecStr, "%1.5f" , Dur3 );
fprintf( fp, "%s Seconds, Sum %I64d, Big_First_32( 0 - 999,999 ).\n"
, SecStr + ( * SecStr == '0' ), X3 );

sprintf( SecStr, "%1.5f" , Dur4 );
fprintf( fp, "%s Seconds, Sum %I64d, htonl( 0 - 999,999 ).\n"
, SecStr + ( * SecStr == '0' ), X4 ); fclose( fp ); }

Nov 22 '05 #347

Hi Olaf, You wrote: << This does the trick in VC++ 2003
int iswapped=0; int iOriginal=0x01234567;
__asm {
mov eax,iOriginal
bswap eax
mov iswapped,eax }

Which translates to:

mov dword ptr [iswapped],0 // int iswapped=0;
mov dword ptr [iOriginal],1234567h // int iOriginal=0x01234567;
// and now the __asm part
mov eax,dword ptr [iOriginal] // mov eax,iOriginal
bswap eax
mov dword ptr [iswapped],eax // mov iswapped,eax

And in a optimizer compiler: mov eax,dword ptr [iOriginal]
and mov dword ptr [iswapped],eax might have been stripped away
since the variables would probaly already exist in eax.

So for those that thought that Assembler died,
it is still there, absorbed into the C++ language. >>

Too bad you don't have MS_CPP_Pro,
You might look for a so_called used or OEM copy on eBay.

I don't trust /Og, wouldn't use it for serious products, too fickle,
but it is fun to play with.

Nov 22 '05 #348

Hi Olaf, Re: * ++ P << 16 | * ++ P << 8 and how | doesn't, but should,
provide a so_called Sequence_Point in C_99, gcc or MS_CPP_7_1,

You told me: << Yes it shoud have worked in my opinion too.
But this is life, nothing is perfect. >>

I think MicroSoft won't implement extra Sequence_Points
for fear of becomming too incompatible with the other compilers.
Which is a real shame, as, no doubt, it's the cause of many a mysterious bug.

I think MS should just add a bunch of additional Sequence_Points
and tell the others to either catch up or go fish.

Speaking of compiler faults,
I say C# is wrong to not support printf(), #define, #include, etc.
Not because I care about old code, but becuase I prefer those operatives.

C++/C#'s String/cout/STL can be handy, no doubt,
but I still prefer doing my own memory management, dynamic lists, etc.
As my HTM_TXT.CPP demonstrates, LoopTo() is just pure flexibility:

#define LoopTo( StopCond ) \
while ( Ch && ( Ch = ( uchar ) * ++ P ) \
&& ! ( Ch2 = ( uchar ) P [ 1 ], StopCond ) )

You recounted: <<
I also discovered one time that, if you use events in a C++ class,
VC++ 2002 [ throws ] an access violation if the class happens
not to have a constructor defined and implemented in the header file.
So, for a week, I struggled with that event thing,
and, funny enough, the examples worked but mine failed.
[ Looking at the assmbly code, I saw that ]
the variables of those events [ weren't getting ] initialized.
Clearly a bug in the C++ compiler. Now my code works fine,
since I now put a complete constructor in the header file. >>

Interesting, I wouldn't have thought to check the disassembly like that,
I'll try that the next time I have a hard_to_find bug ( i.e. soon ).

Re: How you use assembly these days, You wrote: <<
In my case it is 15 years old knowledge.
I only use it to look at the generated code to find bugs in my code
and to optimize my functions to speed up without resorting to assembler.
Or to learn a new language,
because I can compare it to something I already know.

And now I do this with IL assembler generated by .NET. >>

The IL assembler sounds cool to me.

You added: << One thing I discover is that properties are not optimized,
not inlined so that could explain why some C# code could be slower.
But then again if I look at my C++ code of the VC++ 2003 Standard,
none of my properties gets inlined too. And this explains
why my C++ code and C# code are almost the same speed on the same computer
and the same OS and compiled with the same compiler environment.
I hope that The VS 2005 gets a better optimizer for that. >>

I have my MS_CPP_Pro inline stuff, even when debugging,
it hasn't been a problem for me.

Re: x86 assembly, you told me: << In the case of Intel like processors,
the ax, eax register gets specialized for processing things.
It is another name for accumulator. >> ... <<
any operation is done with that register, so a lot of code
is copying registers to the eax register and then moving it back.

Another thing to know is that you cannot access the upper word part of eax.
( or the ebx, ecx, edx )
Only the lower word part [ can ] be split into a high byte and a low byte.

eax is the 32 bit register
ax is the same as LOWORD(eax)
and al would be like LOBYTE(ax)
and ah would be like HIBYTE(ax)

So to get the HIWORD(eax), you must >> 16 to [ access ] the ax part.
Then you can access it.

Typically eax is used for calculating things.
ebx is used as index pointer
ecx is typically used as counter
edx is typically used as destination index pointer.
But in the case of an optimizer compiler
you might lose that relationship. >>

What other registers are there, and how are they restricted ?

You added: << Another thing something like this xor ecx,ecx
is actually saying set ecx to null.
This notation is only one byte and superfast
compared to loading it with a actual value. >>

That much I knew already.

Re: mov ecx, dword ptr [ esp + 18h ]

You concluded: <<
Yes a local variable located at 18h positions from your return address. :-)
And if you get something like this mov ecx, dword ptr [ esp - 18h ]
then it is some parameter passed on from outside your function. >>

That's interesting, - is a parameter, thanks.

Nov 22 '05 #349
> Interesting, I wouldn't have thought to check the disassembly like that,
I'll try that the next time I have a hard_to_find bug ( i.e. soon ).
Most of the times I use it if I have complicated one liners, to find out
what instruction in that part is causing the problem.
And now I do this with IL assembler generated by .NET. >>

The IL assembler sounds cool to me.
It is some kind of OOP version of assembler.
But they don't use registers. They use the stack, it is up to the optimizer
to use the most efficient way of register usage.

IL looks something like this (peudo code):

//x=A+B-C
Push A
Push B
Add
Push C
Sub

A little bit like HP calculators would do to.
As far as I see, the generated IL code in C# does not seem to be optimized.
But the JIT might do that optimizing instead, so when I find time I am going
to check into this.
Typically eax is used for calculating things.
ebx is used as index pointer
ecx is typically used as counter
edx is typically used as destination index pointer.
But in the case of an optimizer compiler
you might lose that relationship. >>

What other registers are there, and how are they restricted ?
This is getting too big for the time that I have to explain all this.
You concluded: <<
Yes a local variable located at 18h positions from your return address. :-) And if you get something like this mov ecx, dword ptr [ esp - 18h ]
then it is some parameter passed on from outside your function. >>

That's interesting, - is a parameter, thanks.

Most of the time eax, ebx, ecx and edx is used for the first 4 parameters
that fit in a 32 bit number, like int, short, byte, and pointers/references)
and then they start using parameters pushed on the stack
Most of the time a result is returned in the eax.

But if you use a different calling convention other rules might apply.
Nov 22 '05 #350

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

7 posts views Thread by tada991 | last post: by
22 posts views Thread by Ramzy Darwish | last post: by
11 posts views Thread by Sam | last post: by
269 posts views Thread by Montrose... | last post: by
15 posts views Thread by Alex L Pavluck | last post: by
6 posts views Thread by Jamiil | last post: by
5 posts views Thread by vinnie | last post: by
reply views Thread by suresh191 | last post: by
reply views Thread by Purva khokhar | last post: by
1 post views Thread by haryvincent176 | last post: by
1 post views Thread by Marylou17 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.