Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Re: Compatibility question

Reply
Thread Tools

Re: Compatibility question

 
 
Keith Thompson
Guest
Posts: n/a
 
      10-23-2012
"BartC" <(E-Mail Removed)> writes:
[...]
> A=B; /* copy by reference */
> *A=*B; /* copy by value */
>
> Where 'reference' and 'value' refer to the targets of the pointers. However
> the copy by value is only one level deep. (To do a proper deep copy involves
> recursing through any nested pointers in the struct, which can point to any
> other kinds of objects. It gets hairy, and would be an entirely different
> kind of language. I don't know if that's what you had in mind.)


What would a "proper" deep copy do with a recursive data structure,
for example where two nodes point to each other?

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
 
 
 
Ben Bacarisse
Guest
Posts: n/a
 
      10-23-2012
"BartC" <(E-Mail Removed)> writes:

> "Steve Thompson" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
>
>> Hypothetically, C might have been designed differently:
>>
>> struct point {
>> int x, y, z;
>> };
>>
>> struct point a, b;
>>
>> a.x = 1;
>> a.y = 2;
>> a.z = 3;

>
> If you're going to the trouble of redesigning the language, at least make it
> possible to write:
>
> a={1,2,3};


You can so something very similar already, though your are obliged to
repeat the type:

a = (struct point){1, 2, 3};

<snip>
--
Ben.
 
Reply With Quote
 
 
 
 
BartC
Guest
Posts: n/a
 
      10-23-2012


"Keith Thompson" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> "BartC" <(E-Mail Removed)> writes:
> [...]
>> A=B; /* copy by reference */
>> *A=*B; /* copy by value */
>>
>> Where 'reference' and 'value' refer to the targets of the pointers.
>> However
>> the copy by value is only one level deep. (To do a proper deep copy
>> involves
>> recursing through any nested pointers in the struct, which can point to
>> any
>> other kinds of objects. It gets hairy, and would be an entirely different
>> kind of language. I don't know if that's what you had in mind.)

>
> What would a "proper" deep copy do with a recursive data structure,
> for example where two nodes point to each other?


That's where it gets even more hairy I guess.

My experience of this is with structures and pointers maintained by the
language, where circular definitions don't exist. The deep copy routine can
still be called recursively though. (In fact it's *because* deep copy is
done by assignments, that the pointers were generally well-behaved; this
could be done without reference counting and without using GC.)

So it probably wouldn't work with explicit pointers controlled by the
programmer.

--
Bartc

 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      10-23-2012
Steve Thompson <(E-Mail Removed)> writes:
> On Tue, Oct 23, 2012 at 12:26:05PM -0700, Keith Thompson wrote:
>> Steve Thompson <(E-Mail Removed)> writes:
>> > On Mon, Oct 22, 2012 at 09:06:39PM +0100, Ben Bacarisse wrote:

>> [...]
>> >> Whatever goes on under the hood (and I'd dispute that 'a' is "really a
>> >> pointer") it's much easier to learn a language in its own terms, at
>> >> least as far as that's possible.
>> >
>> > Well, no. 'a' is never a pointer as such in the terms of the language
>> > syntax, but its treatment by the compiler internally is nominally
>> > equivalent to they way it handles a pointer, with the exception that
>> > the language grammar forbids its use in the program text as a pointer.

>>
>> I don't believe that's true. Do you have some evidence that it is?

>
> The distinction is largely moot. In a practical sense, all variables
> have a value which is stored somewhere. The compiler is making an
> explicit use of a pointer when it does something with the value. The
> problem is that "use" in this context may as well be referring to ether
> or memory and there's no easy way of knowing which it is.


When you say "explicit use of a pointer", do you mean that there's
a pointer *object* somewhere, or are you talking about a pointer
*value*, also known as an "address"?

How much do you know about the internal workings of compilers?

>> > In a simplistic sense, all variables are pointers to a segment of
>> > program data, modifiable or otherwise.


No, a variable is not a pointer to a chunk of memory, it *is* a chunk of
memory (which can contain a value at execution time).

More precisely, the C standard doesn't define the word "variable", but I
presume that a "variable" is a kind of "object", which is defined as a
"region of data storage in the execution environment, the contents of
which can represent values". Not a pointer in sight.

>> > In the real world, variable
>> > values may move around in and from RAM to CPU registers and back while
>> > being identified as a single consistent entity. This helps to
>> > illustrate the difference between a language and its implementation.

>>
>> So a char object is really a pointer to char, an int object is
>> really a pointer to int, and a char** object is really a char**?


Sorry, what I meant to write is that a char** object is really (in your
model) a char***, i.e., a pointer to a char**.

> No, a char ** object is a pointer to a char ** object.


Was that really what you meant to type? I messed up the number of *s,
so I can hardly criticize you for doing the same thing, but I'd like to
know what you meant.

In your model, as I understand it, an int object is really a pointer to
int, or an int*. It would follow that a char** object is really a
pointer to a char**, or a char***. Or am I misunderstanding you?

In fact, an int object is an int object. I find that so obvious
that it seems odd to have to state it. For an operation on such
an object, a compiler might have to generate code that determines
that object's address. That does not in any sense imply that an
int object is "really" a pointer. You can construct a pointer to
an int object, but the pointer and the object it points to are two
different things.

>> I think you're simply adding an extra -- and unnecessary -- level
>> of indirection, and of confusion.
>>
>> There may also be some confusion between pointer *objects* and
>> pointer *values* (i.e., addresses).

>
> Let me say again that I am not talking about addresses as might be
> referenced in object code. Perhaps it will clarify that I am thinking
> of something like the phase space of the compiler as it is building
> the tree representing the source code of the program.


And we're getting even farther afield from the actual semantics of a C
program.

An object doesn't even exist during compilation. Memory for it
is allocated as the program is executed. Pointers (either pointer
objects or pointer values) do not exist until the program executes.
The "phase space" of the compiler is irrelevant.

When you claim that a struct object is "really" a pointer, are you
referring to something that exists internally to a compiler during
compilation? If so, of what possible use is it to understanding
what a struct object is?

>> If I define an object of struct type and perform some operation
>> on it (say, a simple assignment), the generated code might very
>> well refer to the address of the object. There is no *object*
>> of pointer type, either explicitly or implicitly.

>
> That could depend on the way the compiler is designed.


Perhaps. But an object of pointer-to-struct type is a region
of memory holding the address of the struct object. Why would a
compiler allocate and initialize such a pointer object, or generate
code to do so, in the absence of C code to take the addrss of the
struct object?

>> Struct objects are very often manipulated via pointers (simulating
>> by-reference argument passing, for example), but that's a coding
>> convention, not anything inherent to the language.

>
> Agreed.


So where do these "pointers" you keep talking about come from?
In what sense do they exist?

[big snip]

> See my comment above regarding the compiler's phase space, although
> I'm not quite sure that is the best term to use in describing what I
> am thinking.


I'm pretty sure it isn't.

[...]

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
BartC
Guest
Posts: n/a
 
      10-23-2012
"Keith Thompson" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> Steve Thompson <(E-Mail Removed)> writes:


>> No, a char ** object is a pointer to a char ** object.

>
> Was that really what you meant to type? I messed up the number of *s,
> so I can hardly criticize you for doing the same thing, but I'd like to
> know what you meant.
>
> In your model, as I understand it, an int object is really a pointer to
> int, or an int*. It would follow that a char** object is really a
> pointer to a char**, or a char***. Or am I misunderstanding you?
>
> In fact, an int object is an int object. I find that so obvious
> that it seems odd to have to state it. For an operation on such
> an object, a compiler might have to generate code that determines
> that object's address.


For every variable of type T, there will be an address of the variable of
type T* (at least, before compiler optimisation gets to work on it). That
address (or pointer) will be a constant value though, just like the constant
8258 is value of type int that doesn't need storage. Such an address is also
automatically dereferenced by a HLL when you just write the name of the
variable; so the T* aspects of it get overlooked.

That's how you might get your char*** pointer from char**. Of course ST
might have been thinking of an implementation with an actual stored char***
pointer, not a constant one, in which case the address of that, if his
language allows it, would be char****!

>>> I think you're simply adding an extra -- and unnecessary -- level
>>> of indirection, and of confusion.


Whoever said that bit is right. I think a diagram is called for.

--
Bartc

 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      10-24-2012
"BartC" <(E-Mail Removed)> writes:
> "Keith Thompson" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
>> Steve Thompson <(E-Mail Removed)> writes:

>
>>> No, a char ** object is a pointer to a char ** object.

>>
>> Was that really what you meant to type? I messed up the number of *s,
>> so I can hardly criticize you for doing the same thing, but I'd like to
>> know what you meant.
>>
>> In your model, as I understand it, an int object is really a pointer to
>> int, or an int*. It would follow that a char** object is really a
>> pointer to a char**, or a char***. Or am I misunderstanding you?
>>
>> In fact, an int object is an int object. I find that so obvious
>> that it seems odd to have to state it. For an operation on such
>> an object, a compiler might have to generate code that determines
>> that object's address.

>
> For every variable of type T, there will be an address of the variable of
> type T* (at least, before compiler optimisation gets to work on it).


First, the word "variable" is a bit ambiguous. Is it synonymous
with "object"? Usually the meaning is clear enough, but in this
context it's important to be very clear what we're talking about --
and the standard provides no definition of the word "variable".

And what do you mean that "there will be" an address of the variable?
Given a declaration `some_type obj;` the expression &obj can be
evaluated, and is of type some_type* -- but are you saying there's some
sense in which that value exists somewhere just because the object
exists?

> That
> address (or pointer) will be a constant value though, just like the constant
> 8258 is value of type int that doesn't need storage.


Depends on what you mean by "constant". It cannot in general be
evaluated at compile time, as 8258 can. It can be evaluated at link
time if the variable is an object with static storage duration,
but not if it has automatic storage duration. And of course bit
fields and register objects don't have addresses.

> Such an address is also
> automatically dereferenced by a HLL when you just write the name of the
> variable; so the T* aspects of it get overlooked.


The expression `obj` refers to the object of that name. I don't see
how it's useful to think of that expression as taking the address of
`obj` and then dereferencing that address.

> That's how you might get your char*** pointer from char**. Of course ST
> might have been thinking of an implementation with an actual stored char***
> pointer, not a constant one, in which case the address of that, if his
> language allows it, would be char****!


I suspect it's best to let ST explain what he means.

>>>> I think you're simply adding an extra -- and unnecessary -- level
>>>> of indirection, and of confusion.

(that was me)

> Whoever said that bit is right. I think a diagram is called for.


--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
BartC
Guest
Posts: n/a
 
      10-24-2012
"Keith Thompson" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> "BartC" <(E-Mail Removed)> writes:


>> For every variable of type T, there will be an address of the variable of
>> type T*


> First, the word "variable" is a bit ambiguous. Is it synonymous
> with "object"?


I meant 'name'.

> Depends on what you mean by "constant". It cannot in general be
> evaluated at compile time, as 8258 can. It can be evaluated at link
> time if the variable is an object with static storage duration,
> but not if it has automatic storage duration.


It's true that with automatic variables the concept is not so simple; their
addresses might need evaluating. Yet neither are they implemented as actual
pointers in a way that is accessible by the program.

>> Such an address is
>> also
>> automatically dereferenced by a HLL when you just write the name of the
>> variable; so the T* aspects of it get overlooked.

>
> The expression `obj` refers to the object of that name. I don't see
> how it's useful to think of that expression as taking the address of
> `obj` and then dereferencing that address.


There's a connection with what ST might have been on about regarding the
manipulation of struct objects, compared with primitives (in native code,
the dereferencing of an object of arbitrary size, like a struct, is not as
straightforward as with a primitive type).

(Other than that, thinking of A as really meaning *(&A) I have found
extremely useful.)

> I suspect it's best to let ST explain what he means.


I agree.

--
bartc

 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      10-24-2012
"BartC" <(E-Mail Removed)> writes:
> "Keith Thompson" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
>> "BartC" <(E-Mail Removed)> writes:
>>> For every variable of type T, there will be an address of the variable of
>>> type T*

>
>> First, the word "variable" is a bit ambiguous. Is it synonymous
>> with "object"?

>
> I meant 'name'.


Ok, what exactly do you mean by "name"? The standard doesn't give
a single definition of "name", but it seems to mean "identifier".
See, for example, the definitions of "external name" and "internal
name" in N1570 6.4.2.1p5.

Given:

int foobar;

do we have an *object" foobar of type int, but the *variable*
foobar is an identifier with 6 letters? And given:

int foobar;
{
double foobar;
}

do we have only one "variable", because both objects have the same name?

Either I'm completely misunderstanding you, or you have a very
odd definition of the word "variable", and one that's inconsistent
both with the way the standard uses the word in a few footnotes,
and with the idea of something that's "able to vary".

[snip]

>> I suspect it's best to let ST explain what he means.

>
> I agree.


--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      10-24-2012
Steve Thompson <(E-Mail Removed)> writes:
> On Tue, Oct 23, 2012 at 03:53:21PM -0700, Keith Thompson wrote:
>> Steve Thompson <(E-Mail Removed)> writes:
>> > On Tue, Oct 23, 2012 at 12:26:05PM -0700, Keith Thompson wrote:
>> >> Steve Thompson <(E-Mail Removed)> writes:
>> >> > On Mon, Oct 22, 2012 at 09:06:39PM +0100, Ben Bacarisse wrote:
>> >> [...]
>> >> >> Whatever goes on under the hood (and I'd dispute that 'a' is "really a
>> >> >> pointer") it's much easier to learn a language in its own terms, at
>> >> >> least as far as that's possible.
>> >> >
>> >> > Well, no. 'a' is never a pointer as such in the terms of the language
>> >> > syntax, but its treatment by the compiler internally is nominally
>> >> > equivalent to they way it handles a pointer, with the exception that
>> >> > the language grammar forbids its use in the program text as a pointer.
>> >>
>> >> I don't believe that's true. Do you have some evidence that it is?
>> >
>> > The distinction is largely moot. In a practical sense, all variables
>> > have a value which is stored somewhere. The compiler is making an
>> > explicit use of a pointer when it does something with the value. The
>> > problem is that "use" in this context may as well be referring to ether
>> > or memory and there's no easy way of knowing which it is.

>>
>> When you say "explicit use of a pointer", do you mean that there's
>> a pointer *object* somewhere, or are you talking about a pointer
>> *value*, also known as an "address"?

>
> I suppose address is the better term, but that does not work for
> registers.


Neither "address" nor "pointer" works for register objects -- or for bit
fields.

>> How much do you know about the internal workings of compilers?

>
> Precious little. My brain is only starting to think about
> interpreters; I plan to hold off polluting my brain with compiler
> internals until I find a pressing need to write one.


Then I'm mystified by your decision to try to understand C
semantics in terms of compiler internals. There's a perfectly good
definition of C semantics: the ISO C standard; the latest draft
is <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf>.

>> >> > In a simplistic sense, all variables are pointers to a segment of
>> >> > program data, modifiable or otherwise.

>>
>> No, a variable is not a pointer to a chunk of memory, it *is* a chunk of
>> memory (which can contain a value at execution time).
>>
>> More precisely, the C standard doesn't define the word "variable", but I
>> presume that a "variable" is a kind of "object", which is defined as a
>> "region of data storage in the execution environment, the contents of
>> which can represent values". Not a pointer in sight.

>
> My bad, I have assumed that a variable must be distinguished from
> other variables by an address, which implies a pointer of some sort,
> but you might choose to call that an identifier instead.


An identifier is a character string that exists in source code. An
object is a "region of data storage in the execution environment, the
contents of which can represent values". The standard doesn't define
the term "variable", and uses it in that sense only in a few footnotes,
but it consistently uses the word "variable" to refer to objects.

Given:

int obj;
register int reg;
struct {
int member;
int bit_field:8;
}s;

obj, reg, s, s.member, and s.bit_field are all objects (or, perhaps more
precisely, are all names by which we can refer to objects). Not all of
them have addresses. Which of them are "variables" might be an
interesting question, but I don't think it would illumate what we're
talking about. I suggest we stick to the term "object" from now on,
since it has an unambiguous meaning.

> More generally, a value must be distinguished from other values with a
> unique identifier. In a program, we call this identifier a 'named
> variable', which in a sense may be thought of as is its 'address' by
> virtue of its entry in the program's 'dictionary' of identifiers.
> Anything else implies magic of some unspecified/unknowable nature, and
> I'm not all that keen on the idea of magic.


Now you introduce the term "value", which is very different from an
"object". The expression `42`, when evaluated, yields a "value" which
is not associated with any object. And not all objects have names; some
of them are anonymous:

int *ptr = malloc(sizeof *ptr);
// *ptr is an int object with no name of its own

An object defined inside a recursive function will have a single
entry in the compiler's symbol table, but can have multiple
instances, with distinct addresses, during execution. An object
defined in a function that's never called likewise has a single
symbol table entry, but has *no* address during execution.

These are just some of the reasons why using the term "address" to
refer to a compiler symbol table entry (which is what I think you
mean by "its entry in the program's 'dictionary' of identifiers")
is just wrong and confusing.

> This 'address' has distinct qualities in the compiler's representation
> of the program and in the assembled object code, which I suppose are
> representative of distinct, but related ontologies. The standard, of
> course, is not concerned with the philosophy of computer software,
> only its behavior in the execution environment.


The standard is not concerned either with the "philosophy of computer
software" or with the details of compiler implementation.

>> >> > values may move around in and from RAM to CPU registers and back while
>> >> > being identified as a single consistent entity. This helps to
>> >> > illustrate the difference between a language and its implementation.
>> >>
>> >> So a char object is really a pointer to char, an int object is
>> >> really a pointer to int, and a char** object is really a char**?

>>
>> Sorry, what I meant to write is that a char** object is really (in your
>> model) a char***, i.e., a pointer to a char**.
>>
>> > No, a char ** object is a pointer to a char ** object.

>>
>> Was that really what you meant to type? I messed up the number of *s,
>> so I can hardly criticize you for doing the same thing, but I'd like to
>> know what you meant.

>
> I must suggest that the fundamental nature of objects is that they
> have an identifier and existence. Existence implies location,
> especially in a computer program. Proving the proposition that
> identifiers have existence independent of their object I leave as an
> exercise for the student.


You didn't answer my question. And not all objects have identifiers.

>> In your model, as I understand it, an int object is really a pointer to
>> int, or an int*. It would follow that a char** object is really a
>> pointer to a char**, or a char***. Or am I misunderstanding you?

>
> Perhaps you can revisit that question after considering the
> philosophical statements above.


No thanks. Perhaps you can *answer* that question.

>> In fact, an int object is an int object. I find that so obvious
>> that it seems odd to have to state it. For an operation on such
>> an object, a compiler might have to generate code that determines
>> that object's address. That does not in any sense imply that an
>> int object is "really" a pointer. You can construct a pointer to
>> an int object, but the pointer and the object it points to are two
>> different things.

>
> We're using pointer in two different senses: in the sense defined by
> the C standard, and in the sense that an identifier points to
> an object, by definition. The concept of 'pointer' is implicit to the
> idea of 'object'. You seem to be confused by the use of pointer to
> refer to anything other than a C pointer object.


Of course I'm confused by your use of the word "pointer" to refer to
things other than actual pointers. This is comp.lang.c, where we
discuss the C programming language, which is defined by the ISO C
standard, which has an unambiguous meaning for the word "pointer".

And I still don't understand what your other meaning of "pointer" is.
Can you (a) explain exactly what you mean by "pointer", and (b) use a
different word to refer to that concept, to avoid further confusion?

The concept of "pointer" is not implicit in the idea of "object".

> Religions seem to rely on that same kind of confusion to obscure the
> origins and nature of some kinds of religious 'knowledge'.


I'm not interested in discussing religion, at least not here.

> Moreover,
> thinking about philosophy and ontology is all but outlawed today.


Nonsense. But philosophy and ontology are not what this newsgroup is
about. Perhaps you'd be happer in a forum that does discuss philosophy.

Perhaps what you're saying would make sense to someone who has studied
more philosphy than I have.

[snip]

[...]
>> Perhaps. But an object of pointer-to-struct type is a region
>> of memory holding the address of the struct object. Why would a
>> compiler allocate and initialize such a pointer object, or generate
>> code to do so, in the absence of C code to take the addrss of the
>> struct object?

>
> Because it is natural to do so. The fact that your compiler copies
> such structures in assignment contexts (seemingly) one field at a time
> is an artifact of its design. Another compiler might use a form of
> memcpy(), in which case there would have to be a pointer -- just not
> one that you defined explicitly in your source code.


The generated code I posted upthread was not copying the structure a
field at a time, it was copying it a word at a time. But the CPU
instructions a compiler chooses to implement an assignment operation
have nothing to do with the conceptual nature of an object.

>> >> Struct objects are very often manipulated via pointers (simulating
>> >> by-reference argument passing, for example), but that's a coding
>> >> convention, not anything inherent to the language.
>> >
>> > Agreed.

>>
>> So where do these "pointers" you keep talking about come from?
>> In what sense do they exist?


And you haven't answer that question either.

[...]

> I think the philosophical perspective better illustrates what I was
> thinking. The phase space is referential to a program's execution
> environment, which we generally assume to exist, and hence any object
> in that phase space has an address which is, by definition, a pointer.
>
> I hope this makes things clearer.


Not even a little bit.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      10-24-2012
On 10/24/2012 05:38 PM, Keith Thompson wrote:
....
> ... This is comp.lang.c, where we
> discuss the C programming language, which is defined by the ISO C
> standard, which has an unambiguous meaning for the word "pointer".


Well - sort of. In different contexts it uses the term "pointer" to mean
either a pointer object or a pointer value. I've found it useful,
particularly in this newsgroup, to be more careful about that
distinction than the standard itself is.
 
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
Dell RAM compatibility question Jim Whitman Computer Support 3 10-26-2005 05:39 PM
memory compatibility question Sal221 Computer Support 1 05-11-2005 08:16 AM
Cross Browser compatibility question tom HTML 46 10-28-2004 05:20 PM
Canon 550EX Speedlite Flash Compatibility Question Jonathan Stryker Digital Photography 6 11-10-2003 02:08 PM
Browser compatibility question Raymond Lee HTML 8 10-15-2003 11:13 PM



Advertisments