Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Why this fix work ?

Reply
Thread Tools

Why this fix work ?

 
 
linq936@hotmail.com
Guest
Posts: n/a
 
      06-19-2007
Hi,
My program crashes on Linux64 platform. The crash only happens on
optimized compiling, if I compile the code in debug mode, it works
fine. If I compile the code on Linux 32 platform, neither debug mode
nor optimized mode crashes.

In tracking the issue, I finally narrow the code into something like
this:

int my_func(ClientData client_data,
Tcl_Interp* interp,
Tcl_Obj* CONST argv[]) {

< some code >

MyClass* myobj;
Tcl_GetIntFromObj(interp, argv[1], (int *) &myobj);


You can see this is to interact with TCL through C/TCL interface,
you can also see that myobj is not initialized before used.

I tested changing the code to:

MyClass* myobj = NULL;
Tcl_GetIntFromObj(interp, argv[1], (int *) &myobj);

Now it works.

But this does not make sense to me. I check into TCL 8.4 source code
for this function, Tcl_GetIntFromObj(), the simplified version is like
this,

int
Tcl_GetIntFromObj(interp, objPtr, intPtr)
Tcl_Interp *interp; /* Used for error reporting if not NULL. */
register Tcl_Obj *objPtr; /* The object from which to get a int.
*/
register int *intPtr; /* Place to store resulting int. */
{

< some code>

*intPtr = (int)w; <=== This is the only place intPtr is used
return TCL_OK;
}

I do not see why my change, give myobj an initial assignment, could
make difference upon this TCL code except the following 2
obsersavations:

1. If I do not assign myobj to NULL, compiler may give it a wild
address which in optimized mode always points to some not-allowed
address?

2. The TCL function declares the argument as "register int *intPtr",
I never use "register" keyword in my C programming, not sure if it has
a role over here.

Would really appreciate if you could shed some light here.

 
Reply With Quote
 
 
 
 
Walter Roberson
Guest
Posts: n/a
 
      06-20-2007
In article <. com>,
<> wrote:
> My program crashes on Linux64 platform. The crash only happens on
>optimized compiling, if I compile the code in debug mode, it works
>fine. If I compile the code on Linux 32 platform, neither debug mode
>nor optimized mode crashes.


> MyClass* myobj;
> Tcl_GetIntFromObj(interp, argv[1], (int *) &myobj);


> But this does not make sense to me. I check into TCL 8.4 source code
>for this function, Tcl_GetIntFromObj(), the simplified version is like
>this,


>int
>Tcl_GetIntFromObj(interp, objPtr, intPtr)
> Tcl_Interp *interp; /* Used for error reporting if not NULL. */
> register Tcl_Obj *objPtr; /* The object from which to get a int.
>*/
> register int *intPtr; /* Place to store resulting int. */
>{



> *intPtr = (int)w; <=== This is the only place intPtr is used


You are writing an object the width of an int into an object defined
to be the width of a pointer (MyClass* myobj). Possibly your int
is wider than your pointer ?
--
Okay, buzzwords only. Two syllables, tops. -- Laurie Anderson
 
Reply With Quote
 
 
 
 
Ian Collins
Guest
Posts: n/a
 
      06-20-2007
Walter Roberson wrote:
> In article <. com>,
> <> wrote:
>> My program crashes on Linux64 platform. The crash only happens on
>> optimized compiling, if I compile the code in debug mode, it works
>> fine. If I compile the code on Linux 32 platform, neither debug mode
>> nor optimized mode crashes.

>
>> MyClass* myobj;
>> Tcl_GetIntFromObj(interp, argv[1], (int *) &myobj);

>
>> But this does not make sense to me. I check into TCL 8.4 source code
>> for this function, Tcl_GetIntFromObj(), the simplified version is like
>> this,

>
>> int
>> Tcl_GetIntFromObj(interp, objPtr, intPtr)
>> Tcl_Interp *interp; /* Used for error reporting if not NULL. */
>> register Tcl_Obj *objPtr; /* The object from which to get a int.
>> */
>> register int *intPtr; /* Place to store resulting int. */
>> {

>
>
>> *intPtr = (int)w; <=== This is the only place intPtr is used

>
> You are writing an object the width of an int into an object defined
> to be the width of a pointer (MyClass* myobj). Possibly your int
> is wider than your pointer ?


More likely the other way round, writing say a 32 bit int into a 64 bit
pointer, leaving half of the bits untouched. Initialising the pointer
to all bits zero clears these bits, yielding a different value after the
function call.

--
Ian Collins.
 
Reply With Quote
 
Chris Torek
Guest
Posts: n/a
 
      06-20-2007
In article <. com>
<> wrote:
> My program crashes on Linux64 platform.


In theory, the platform should not matter. In practice, since your
code uses undefined (by the standard) behavior, it does.

For discussion purposes, then, I will leave the above in, and add
another two notes:

- On your machine, pointers (regardless of the pointed-to type)
are 64 bits wide.

- On your machine, "int" is 32 bits wide.

>The crash only happens on optimized compiling, if I compile the
>code in debug mode, it works fine.


This is basically a matter of luck -- bad luck that it works at
all, good luck that it fails sometimes, and bad luck that the
failure occurs in the harder-to-debug version.

> In tracking the issue, I finally narrow the code into something like
>this:


"Something like" is dangerous -- it is usually best to show the
actual failing code. (In this case, that may not be possible; and
there was enough information here, fortunately.)

> int my_func(ClientData client_data,
> Tcl_Interp* interp,
> Tcl_Obj* CONST argv[]) {
>
> < some code >
>
> MyClass* myobj;


Note that "myobj" has type "pointer to MyClass", where "MyClass"
is presumably a typedef-alias for some other type. Since, on this
particular machine, all pointers are 64 bits, "myobj" is itself 64
bits wide. The 64 bits are not initialized, and hence may be full
of apparently-random trash (although if you are un?lucky, they may
be all-zeros or otherwise consistent).

> Tcl_GetIntFromObj(interp, argv[1], (int *) &myobj);


Here, the third argument to Tcl_GetIntFromObj() is the value of
the address of "myobj", but converted to "int *". In other words,
this "int *" -- which, at least logically speaking, ought to point
to an "int", which would be 32 bits wide -- actually points to a
"MyClass *", which is actually 64 bits wide.

The fact that you use (and need) a cast here is a very bad sign.

Next, you have parts of Tcl_GetIntFromObj() here:

>int
>Tcl_GetIntFromObj(interp, objPtr, intPtr)
> Tcl_Interp *interp; /* Used for error reporting if not NULL. */
> register Tcl_Obj *objPtr; /* The object from which to get a int. */
> register int *intPtr; /* Place to store resulting int. */
>{
>
> < some code>
>
> *intPtr = (int)w; <=== This is the only place intPtr is used


So Tcl_GetIntFromObj() really does set the 32 bits at *intPtr to
some 32-bit "int" value.

Since the actual object ("myobj") is 64 bits, whatever this does
is clearly not right. You need to set all 64 bits.

> I tested changing the code to:
>
> MyClass* myobj = NULL;
> Tcl_GetIntFromObj(interp, argv[1], (int *) &myobj);
>
> Now it works.


Well, that too is luck (but is it "good luck" or "bad luck"?).
Now you have initialized all 64 bits of "myobj", then changed 32
of the 64. The result might sometimes be correct, but is probably
wrong at least sometimes, if not often.

A correct *call* to Tcl_GetIntFromObj() should not need a cast.
For instance, if you really do want to get an "int":

int tmp;
...
Tcl_GetIntFromObj(interp, argv[1], &tmp);

If that "int" can then be somehow transformed into a pointer --
exactly how, I do not know; that is up to you -- you can then
do that:

MyClass *convert_int_to_obj(int);

MyClass *myobj;
int tmp;
...
Tcl_GetIntFromObj(interp, argv[1], &tmp);
myobj = convert_int_to_obj(tmp);

Note that this code contains no casts. (It still ignores the
"int" return value from Tcl_GetIntFromObj(), though.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
 
Reply With Quote
 
linq936@hotmail.com
Guest
Posts: n/a
 
      06-20-2007
I replied earlier through groups.google, but do not see it, so I post
again. Please scroll to the bottom.


On Jun 19, 7:39 pm, Chris Torek <nos...@torek.net> wrote:
> In article <1182296273.993929.15...@z28g2000prd.googlegroups. com>
>
> <linq...@hotmail.com> wrote:
> > My program crashes on Linux64 platform.

>
> In theory, the platform should not matter. In practice, since your
> code uses undefined (by the standard) behavior, it does.
>
> For discussion purposes, then, I will leave the above in, and add
> another two notes:
>
> - On your machine, pointers (regardless of the pointed-to type)
> are 64 bits wide.
>
> - On your machine, "int" is 32 bits wide.
>
> >The crash only happens on optimized compiling, if I compile the
> >code in debug mode, it works fine.

>
> This is basically a matter of luck -- bad luck that it works at
> all, good luck that it fails sometimes, and bad luck that the
> failure occurs in the harder-to-debug version.
>
> > In tracking the issue, I finally narrow the code into something like
> >this:

>
> "Something like" is dangerous -- it is usually best to show the
> actual failing code. (In this case, that may not be possible; and
> there was enough information here, fortunately.)
>
> > int my_func(ClientData client_data,
> > Tcl_Interp* interp,
> > Tcl_Obj* CONST argv[]) {

>
> > < some code >

>
> > MyClass* myobj;

>
> Note that "myobj" has type "pointer to MyClass", where "MyClass"
> is presumably a typedef-alias for some other type. Since, on this
> particular machine, all pointers are 64 bits, "myobj" is itself 64
> bits wide. The 64 bits are not initialized, and hence may be full
> of apparently-random trash (although if you are un?lucky, they may
> be all-zeros or otherwise consistent).
>
> > Tcl_GetIntFromObj(interp, argv[1], (int *) &myobj);

>
> Here, the third argument to Tcl_GetIntFromObj() is the value of
> the address of "myobj", but converted to "int *". In other words,
> this "int *" -- which, at least logically speaking, ought to point
> to an "int", which would be 32 bits wide -- actually points to a
> "MyClass *", which is actually 64 bits wide.
>
> The fact that you use (and need) a cast here is a very bad sign.
>
> Next, you have parts of Tcl_GetIntFromObj() here:
>
> >int
> >Tcl_GetIntFromObj(interp, objPtr, intPtr)
> > Tcl_Interp *interp; /* Used for error reporting if not NULL. */
> > register Tcl_Obj *objPtr; /* The object from which to get a int. */
> > register int *intPtr; /* Place to store resulting int. */
> >{

>
> > < some code>

>
> > *intPtr = (int)w; <=== This is the only place intPtr is used

>
> So Tcl_GetIntFromObj() really does set the 32 bits at *intPtr to
> some 32-bit "int" value.
>
> Since the actual object ("myobj") is 64 bits, whatever this does
> is clearly not right. You need to set all 64 bits.
>
> > I tested changing the code to:

>
> > MyClass* myobj = NULL;
> > Tcl_GetIntFromObj(interp, argv[1], (int *) &myobj);

>
> > Now it works.

>
> Well, that too is luck (but is it "good luck" or "bad luck"?).
> Now you have initialized all 64 bits of "myobj", then changed 32
> of the 64. The result might sometimes be correct, but is probably
> wrong at least sometimes, if not often.
>
> A correct *call* to Tcl_GetIntFromObj() should not need a cast.
> For instance, if you really do want to get an "int":
>
> int tmp;
> ...
> Tcl_GetIntFromObj(interp, argv[1], &tmp);
>
> If that "int" can then be somehow transformed into a pointer --
> exactly how, I do not know; that is up to you -- you can then
> do that:
>
> MyClass *convert_int_to_obj(int);
>
> MyClass *myobj;
> int tmp;
> ...
> Tcl_GetIntFromObj(interp, argv[1], &tmp);
> myobj = convert_int_to_obj(tmp);
>
> Note that this code contains no casts. (It still ignores the
> "int" return value from Tcl_GetIntFromObj(), though.)
> --
> In-Real-Life: Chris Torek, Wind River Systems
> Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
> email: forget about it http://web.torek.net/torek/index.html
> Reading email is like searching for food in the garbage, thanks to spam


Chris,
There is no word I can express my appreciation.

Thank you!

Your suggestion makes sense to me, but one thing I do not quite get.

I initialize the pointer to 0 :

MyClass* myobj = NULL;

This is means all 64 bits are '\0' now, later when it is assigned with
a 32 bit data, it is only the least significant 32 bits are updated
and the the other 32 bit keep 0. If this is correct, then there is no
potential problem here. Why do you say " The result might sometimes be
correct, but is probably wrong at least sometimes"? As I see, it
should always be right.

I tested the following code on 32 bit Linux machine:

#include <stdio.h>

void func(unsigned char* cp){
*cp = 255;
}

int main(){
unsigned int i = 0x80000000;
printf("before func(), i=0x%x.\n", i);
func( (unsigned char*) &i );
printf("after func(), i=0x%x.\n", i);

return 0;
}

And the print out is as expected:

before func(), i=0x80000000.
after func(), i=0x800000ff.


Looking forward to your further teaching.

 
Reply With Quote
 
Ian Collins
Guest
Posts: n/a
 
      06-20-2007
wrote:
> On Jun 19, 7:39 pm, Chris Torek <nos...@torek.net> wrote:
>
>> Well, that too is luck (but is it "good luck" or "bad luck"?).
>> Now you have initialized all 64 bits of "myobj", then changed 32
>> of the 64. The result might sometimes be correct, but is probably
>> wrong at least sometimes, if not often.
>>
>> A correct *call* to Tcl_GetIntFromObj() should not need a cast.
>> For instance, if you really do want to get an "int":
>>
>> int tmp;
>> ...
>> Tcl_GetIntFromObj(interp, argv[1], &tmp);
>>
>> If that "int" can then be somehow transformed into a pointer --
>> exactly how, I do not know; that is up to you -- you can then
>> do that:
>>
>> MyClass *convert_int_to_obj(int);
>>
>> MyClass *myobj;
>> int tmp;
>> ...
>> Tcl_GetIntFromObj(interp, argv[1], &tmp);
>> myobj = convert_int_to_obj(tmp);
>>
>> Note that this code contains no casts. (It still ignores the
>> "int" return value from Tcl_GetIntFromObj(), though.)

>
> Chris,
> There is no word I can express my appreciation.
>
> Thank you!
>
> Your suggestion makes sense to me, but one thing I do not quite get.
>
> I initialize the pointer to 0 :
>
> MyClass* myobj = NULL;
>
> This is means all 64 bits are '\0' now, later when it is assigned with
> a 32 bit data, it is only the least significant 32 bits are updated
> and the the other 32 bit keep 0. If this is correct, then there is no
> potential problem here. Why do you say " The result might sometimes be
> correct, but is probably wrong at least sometimes"? As I see, it
> should always be right.
>

What happens on a system where a 64 bit pointer has something other that
all bits zero in the bits that you are not writing?

You should follow Chris' advice and make the code "clean" without the
casts, which may be hiding something nasty. If this proves difficult,
you are doing something wrong.

--
Ian Collins.
 
Reply With Quote
 
linq936@hotmail.com
Guest
Posts: n/a
 
      06-20-2007
On Jun 19, 11:38 pm, Ian Collins <ian-n...@hotmail.com> wrote:
> linq...@hotmail.com wrote:
> > On Jun 19, 7:39 pm, Chris Torek <nos...@torek.net> wrote:

>
> >> Well, that too is luck (but is it "good luck" or "bad luck"?).
> >> Now you have initialized all 64 bits of "myobj", then changed 32
> >> of the 64. The result might sometimes be correct, but is probably
> >> wrong at least sometimes, if not often.

>
> >> A correct *call* to Tcl_GetIntFromObj() should not need a cast.
> >> For instance, if you really do want to get an "int":

>
> >> int tmp;
> >> ...
> >> Tcl_GetIntFromObj(interp, argv[1], &tmp);

>
> >> If that "int" can then be somehow transformed into a pointer --
> >> exactly how, I do not know; that is up to you -- you can then
> >> do that:

>
> >> MyClass *convert_int_to_obj(int);

>
> >> MyClass *myobj;
> >> int tmp;
> >> ...
> >> Tcl_GetIntFromObj(interp, argv[1], &tmp);
> >> myobj = convert_int_to_obj(tmp);

>
> >> Note that this code contains no casts. (It still ignores the
> >> "int" return value from Tcl_GetIntFromObj(), though.)

>
> > Chris,
> > There is no word I can express my appreciation.

>
> > Thank you!

>
> > Your suggestion makes sense to me, but one thing I do not quite get.

>
> > I initialize the pointer to 0 :

>
> > MyClass* myobj = NULL;

>
> > This is means all 64 bits are '\0' now, later when it is assigned with
> > a 32 bit data, it is only the least significant 32 bits are updated
> > and the the other 32 bit keep 0. If this is correct, then there is no
> > potential problem here. Why do you say " The result might sometimes be
> > correct, but is probably wrong at least sometimes"? As I see, it
> > should always be right.

>
> What happens on a system where a 64 bit pointer has something other that
> all bits zero in the bits that you are not writing?
>
> You should follow Chris' advice and make the code "clean" without the
> casts, which may be hiding something nasty. If this proves difficult,
> you are doing something wrong.
>
> --
> Ian Collins.


I need more clarification here, let us translate the code into another
presentation:
MyClass* myobj = NULL; ==> myobj = 0x00000000_00000000
<during that TCL function call> ==> myobj = 0x00000000_########

So basically what you and Chris say is that after the TCL function
call, the first 32 bit of myobj might not be all zero? How come? Is
this compiler dependent?

2nd question is about C/TCL communication. MyClass is a struct type
which includes pretty complex data. Basically I have TCL script to
define the data and return it back to C. The protocol between C and
TCL is that, the data is in memory, the interface passes an integer
pointer to C code, that pointer points to the memory location of the
data defined in the memory, and user C code casts the integer pointer
as the corresponding type pointer.

It seems to me the whole point of you and Chris is that cast because
we can do nothing on how TCL passes memory pointer to C and because of
the inequality of 32 bit and 64 bit, we must make sure the extra 32
bit must be zero, then does the following descriptive code make sense:

MyClass *convert_int_to_obj(int i){
int my_type_size = sizeof(MyClass*);
int int_size = sizeof(i);
int total_bit_diff = ( my_type_size - int_size) * 8;

MyClass* ptr = NULL;
(&ptr) = i; <== this may not be compiler allowed, just for
description

for ( int j=0; j<total_bit_diff; j++ ){
< assign ptr's the most significant bits to sero>
}

return ptr;
}

 
Reply With Quote
 
Walter Roberson
Guest
Posts: n/a
 
      06-20-2007
In article < .com>,
<> wrote:

>I need more clarification here, let us translate the code into another
>presentation:
>MyClass* myobj = NULL; ==> myobj = 0x00000000_00000000
><during that TCL function call> ==> myobj = 0x00000000_########


>So basically what you and Chris say is that after the TCL function
>call, the first 32 bit of myobj might not be all zero? How come? Is
>this compiler dependent?


There is an additional complication.

Suppose myobj is M bits wide, and an int is N bits wide, and for
now assume that M > N. When you take the address of myobj and cast
that address to int* and write through that int*, you are writing
the N bits from the beginning of myobj, because C makes promises
about how addresses increase. But the N bits that are stored from
the beginning of myobj are not necessary the "most significant"
or even the "least significant" bits of myobj when myobj is
interpreted in its full M bits as another kind of value.

It is, for example, allowed that the byte order for an int (assuming
for a second that an int is two bytes) is 2 1 and that the byte order
for a long (assuming for a second that a long is four bytes) is 4 2 1 3,
so setting the first two bytes of the memory via an int could end up
setting the second and fourth bytes of the long, leaving the first
and third bytes of the long as whatever they had before (or leaving
it in a trap state if the OS micro-manages information about which
bytes have been initialized, which is possible.)

--
"law -- it's a commodity"
-- Andrew Ryan (The Globe and Mail, 2005/11/26)
 
Reply With Quote
 
linq936@hotmail.com
Guest
Posts: n/a
 
      06-20-2007
On Jun 20, 10:19 am, rober...@ibd.nrc-cnrc.gc.ca (Walter Roberson)
wrote:
> In article <1182348735.573241.259...@o11g2000prd.googlegroups .com>,
>
> <linq...@hotmail.com> wrote:
> >I need more clarification here, let us translate the code into another
> >presentation:
> >MyClass* myobj = NULL; ==> myobj = 0x00000000_00000000
> ><during that TCL function call> ==> myobj = 0x00000000_########
> >So basically what you and Chris say is that after the TCL function
> >call, the first 32 bit of myobj might not be all zero? How come? Is
> >this compiler dependent?

>
> There is an additional complication.
>
> Suppose myobj is M bits wide, and an int is N bits wide, and for
> now assume that M > N. When you take the address of myobj and cast
> that address to int* and write through that int*, you are writing
> the N bits from the beginning of myobj, because C makes promises
> about how addresses increase. But the N bits that are stored from
> the beginning of myobj are not necessary the "most significant"
> or even the "least significant" bits of myobj when myobj is
> interpreted in its full M bits as another kind of value.
>
> It is, for example, allowed that the byte order for an int (assuming
> for a second that an int is two bytes) is 2 1 and that the byte order
> for a long (assuming for a second that a long is four bytes) is 4 2 1 3,
> so setting the first two bytes of the memory via an int could end up
> setting the second and fourth bytes of the long, leaving the first
> and third bytes of the long as whatever they had before (or leaving
> it in a trap state if the OS micro-manages information about which
> bytes have been initialized, which is possible.)
>
> --
> "law -- it's a commodity"
> -- Andrew Ryan (The Globe and Mail, 2005/11/26)


Walter,
Thanks.

It is surprise to know the memory layout could be different as I
expected, but it is hard for me to imagine how this will work. For
example, let's say one integer is 2 byte in length and the layout is 2
1 and a long is 4 2 1 3. Then if I have the following code:

int i = 0x1001
long l = 0x10110001
char* p = &i; <== now p points to byte 2 of i which is 0x10?
p++; <== now p points to byte 1 of i which is 0x01?
char* p = &l; <== now p points to byte 4 of i which is 0x10?
p++; <== now p points to byte 2 of i which is 0x00?

I think I see code which uses smaller type pointer to access larger
type data, if the order is totally dependent on compiler/CPU
implementation, then such code is not portable. Is that right?

Anyway, i am even more confused what is the best way to write clean
code here. I gave an example code in my previous post to implement
convert_int_to_obj(), but if I can not assume safely the memory
layout, I can not think of that function implementation.

Any idea?


 
Reply With Quote
 
Walter Roberson
Guest
Posts: n/a
 
      06-20-2007
In article < .com>,
<> wrote:

> I think I see code which uses smaller type pointer to access larger
>type data, if the order is totally dependent on compiler/CPU
>implementation, then such code is not portable. Is that right?


Right. You can probe the ordering and make appropriate adjustments
by, for example, long T = 0x01020304; unsigned char *P = &T;
then P[0] tells you which value byte of T is stored at the lowest
address, P[1] tells you which value byte of T is stored at the
next address, and so on.


> Anyway, i am even more confused what is the best way to write clean
>code here. I gave an example code in my previous post to implement
>convert_int_to_obj(), but if I can not assume safely the memory
>layout, I can not think of that function implementation.


I haven't studied the thread in detail, but part of the problem
in the original code seemed to be that you were perhaps going
indirect one too many times. You had myobj as a pointer (value
uninitialized), and you were passing the -address- of myobj
down to the lower level, and setting what was at that pointer
to be an int. But what is at that pointer is the address (pointer) myobj,
not any storage for myobj. Your code would have made more
sense if you had had

SomeType *myobj = malloc(sizeof *myobj);
TCL_call( (int *)myobj );

then when TCL_call went indirect on the pointer and stored an int
there, the storage it would have been setting would have been the
malloc'd storage, not the pointer myobj.
--
If you lie to the compiler, it will get its revenge. -- Henry Spencer
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
why why why why why Mr. SweatyFinger ASP .Net 4 12-21-2006 01:15 PM
findcontrol("PlaceHolderPrice") why why why why why why why why why why why Mr. SweatyFinger ASP .Net 2 12-02-2006 03:46 PM
Xah's Edu Corner: The Concepts and Confusions of Pre-fix, In-fix, Post-fix and Fully Functional Notations Xah Lee Perl Misc 21 03-21-2006 07:02 AM
Xah's Edu Corner: The Concepts and Confusions of Pre-fix, In-fix, Post-fix and Fully Functional Notations Xah Lee Python 23 03-21-2006 07:02 AM
Xah's Edu Corner: The Concepts and Confusions of Pre-fix, In-fix, Post-fix and Fully Functional Notations Xah Lee Java 22 03-21-2006 07:02 AM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57