reference type for C

G

glen herrmannsfeldt

(snip, I wrote)
I am sorry, but I am not familiar enough with Fortran 66 to determine
that with any certainty.
My initial guess would be 10, but I would not be surprised if it should
be 5 or 11.
And if it is about the value in the register, I would have no problems
with that being 20, 40, or even 0.

According to the Fortran 66 standard (changed in Fortran 77) the DO
variable is undefined on normal end of the loop. If you GOTO, or
otherwise exit the loop, then it is defined.

In this case, it is usual for good compilers to keep I in a register
and never store it in the actual I.

As with C undefined behavior, standard conforming programs aren't
allowed to test it, but 5 and 11 are the usual possibilities.
When kept in a register, it might increment by the appropriate
byte increment, so no actual value to store.
But I don't see what that has to do with what a optimizer can
do with two semantically equivalent pieces of code written
in different styles.

Yes, it was to note that the way compilers see code isn't always
the way humans do.

-- glen
 
J

James Kuyper

I think you mean "cout << ...".


Does it? As far as I know, the overloaded << operator takes two
arguments of types whatever-the-type-of-cout-is and some-other-type, and
returns a result of type whatever-the-type-of-cout-is. It doesn't need
to modify either operand.

cout has the type std::eek:stream.

cout manages a buffer that gets filled in as data is written, and which
periodically gets dumped to the output file. That buffer itself, and the
information needed to manage it, both get updated every time you write
to the file. If something goes wrong during an attempt to write to the
file, a flag must also be set.
Similarly, the C equivalent:

fprintf(some_file, "%s\n", "Hello World!");

does not (and cannot) modify its first argument, which is of type FILE*.
If the type whatever-the-type-of-cout-is is similar to FILE*, there's no
need for << to modify it.

As far as I know, everything I said about cout is equally true of
*some_file.

The main difference between C's FILE and C++'s std::eek:fstream are that
the C++ standard gives you a lot more information about the internal
workings of std::eek:fstream. std::eek:fstream is a typedef for
std::basic_ofstream<char, std::char_traits<char> >. std::basic_ofstream
is derived from std::basic_ostream, which is in turn derived from
std::basic_ios. std::basic_ofstream uses a std::basic_filebuf object,
which is derived from std::basic_streambuf.

The interactions between all of those different classes are explained in
sufficient detail to allow you to customize the behavior by
a) templating with a different traits class
b) deriving your own class from one of the standard ones
c) implementing your own class that does the same thing as one of the
standard ones, but uses a different base class.

setvbuf() is pretty much the upper limit for customization of FILE* objects.
 
K

Keith Thompson

James Kuyper said:
cout has the type std::eek:stream.
Ok.

cout manages a buffer that gets filled in as data is written, and which
periodically gets dumped to the output file. That buffer itself, and the
information needed to manage it, both get updated every time you write
to the file. If something goes wrong during an attempt to write to the
file, a flag must also be set.

Sure, but that doesn't address the question of whether the std::eek:stream
object itself is modified by the "<<" operator.

I can imagine the type std::eek:stream being implemented as a struct or
class containing pointers to other data, and operator<< being written so
that it modifies the pointed-to data, but never modifies the
std::eek:stream object itself.

In other words, given a particular implementation of std::eek:stream, you
could write a function that takes a non-reference non-pointer argument
of type std::eek:stream and does just what operator<< does. I don't see
that it *needs* to be passed by reference -- though it could well be
convenient to do so.

(As it happens, an experiment on my system indicates that the contents
of std::cout *are* modified by a call to operator<<, but that doesn't
prove anything.)
As far as I know, everything I said about cout is equally true of
*some_file.

Obviously fprintf can modify *some_file. It just can't modify
some_file.
The main difference between C's FILE and C++'s std::eek:fstream are that
the C++ standard gives you a lot more information about the internal
workings of std::eek:fstream. std::eek:fstream is a typedef for
std::basic_ofstream<char, std::char_traits<char> >. std::basic_ofstream
is derived from std::basic_ostream, which is in turn derived from
std::basic_ios. std::basic_ofstream uses a std::basic_filebuf object,
which is derived from std::basic_streambuf.

The interactions between all of those different classes are explained in
sufficient detail to allow you to customize the behavior by
a) templating with a different traits class
b) deriving your own class from one of the standard ones
c) implementing your own class that does the same thing as one of the
standard ones, but uses a different base class.

I don't think that implies that the customization must be done by
modifying the std::eek:stream object itself; it could just modify things
that it points to.
 
K

Keith Thompson

glen herrmannsfeldt said:
As you say, it doesn't and can't modify its argument (some_file),
but it can modify (*some_file), and sort of by definition modifies
the actual file (disk, printer, terminal screen).

Certainly. Modifications of the actual file are side effects.
Would you say it doesn't modify the argument of type (FILE*) but
does modify the pointee of type (FILE)?

I'd say it doesn't and can't modify the FILE*, and it can but may or may
not modify the FILE. A FILE object might itself be, or contain, a
pointer to some other data structure that gets modified.
 
R

roland.arthaud

In the case of :

int i = 5;
int& ri = i;
foo(ri);

I'd like to know whether foo is going to change my i (or any example with
something more elaborate than with an int)

Whereas with the file I/O mentioned in the previous posts, FILE or cout are opaque to the caller and must change state to perform the requested action.
It is not the same as changing the caller's own data.
 
J

James Kuyper

On 05/22/2013 03:38 PM, Keith Thompson wrote:
....
I can imagine the type std::eek:stream being implemented as a struct or
class containing pointers to other data, and operator<< being written so
that it modifies the pointed-to data, but never modifies the
std::eek:stream object itself.

In other words, given a particular implementation of std::eek:stream, you
could write a function that takes a non-reference non-pointer argument
of type std::eek:stream and does just what operator<< does. I don't see
that it *needs* to be passed by reference -- though it could well be
convenient to do so.

(As it happens, an experiment on my system indicates that the contents
of std::cout *are* modified by a call to operator<<, but that doesn't
prove anything.)

You're quite correct; for that matter, the same true of *stdout.

However, every function that the C++ standard defines as causing output
through a std::eek:stream object involves either a non-const member
function or a function that takes the std::eek:stream object as a non-const
reference. Therefore, a conforming implementation is allowed (but not
required) to define std::cout as having data members that are modified
as a result of output, and well-formed code must not be written in such
away as to be incompatible with such an implementation.

....
I don't think that implies that the customization must be done by
modifying the std::eek:stream object itself; it could just modify things
that it points to.

I brought up customization just to point out the biggest difference
between <iostream> and <stdio.h>. I was contrasting that big difference
with the fact that std::cout and *stdout share the characteristic of
possibly (but not necessarily) being directly modified by output. I had
not intended to imply that the greater customizability of <iostream>
requires std::cout to have data members that are modified by output.
 
K

Keith Thompson

James Kuyper said:
On 05/22/2013 03:38 PM, Keith Thompson wrote:
...

You're quite correct; for that matter, the same true of *stdout.

However, every function that the C++ standard defines as causing output
through a std::eek:stream object involves either a non-const member
function or a function that takes the std::eek:stream object as a non-const
reference. Therefore, a conforming implementation is allowed (but not
required) to define std::cout as having data members that are modified
as a result of output, and well-formed code must not be written in such
away as to be incompatible with such an implementation.

Agreed.

I was making a fairly narrow point (and probably not a particularly
...> Consider this basic snippet:
...>
...> cin << "Hello World!" << endl;
...>
...> That calls operator<<() twice, and in both cases, the function modifies
...> its first reference argument (cin); it cannot work any other way.

I was simply disputing that claim that operator<< can only work by
modifying cin (well, actually cout). (It's likely that most
implementations do modify it.)

[...]
 
S

Stephen Sprunk

I think you mean "cout << ...".

That's what I get for changing my example halfway through writing...
Does it? As far as I know, the overloaded << operator takes two
arguments of types whatever-the-type-of-cout-is and some-other-type,
and returns a result of type whatever-the-type-of-cout-is. It
doesn't need to modify either operand.

It necessarily modifies cout, meaning that argument must be passed by
(non-const) reference.
Similarly, the C equivalent:

fprintf(some_file, "%s\n", "Hello World!");

does not (and cannot) modify its first argument, which is of type
FILE*. If the type whatever-the-type-of-cout-is is similar to FILE*,
there's no need for << to modify it.

A key difference is that cout is _not_ itself of pointer type, whereas
stdout is.

Imagine if stdout were the actual stream object rather than a
pointer-to-object. In that case, you would need to write:

fprintf(&stdout, ...);

Likewise, without references, the C++ version would need to be this to
get pass-by-pointer semantics:

*cout << ...;

Perhaps the example would be cleaner if we looked at operator+=(), which
obviously must modify its first (non-const reference) argument?

S
 
S

Stephen Sprunk

In the case of :

int i = 5;
int& ri = i;
foo(ri);

I'd like to know whether foo is going to change my i (or any example
with something more elaborate than with an int)

A better example:

int i = 5;
foo(i);

If foo() takes a non-const reference argument, it could change i in the
caller; a C programmer would only expect that to be possible if the call
looked like this:

int i = 5;
foo(&i);

S
 
K

Keith Thompson

Stephen Sprunk said:
That's what I get for changing my example halfway through writing...


It necessarily modifies cout, meaning that argument must be passed by
(non-const) reference.

Why must it necessarily modify cout?
A key difference is that cout is _not_ itself of pointer type, whereas
stdout is.

But what if cout is of some class/struct type that has a pointer as one
of its members? Obviously cout << "Hello World!" has to modify
*something*, such as the current position in the output stream and
possibly an error indicator. But why does the data being changed have
to be part of the object named "cout"?

I'm not saying it would necessarily make sense to have that added level
of indirection; I just don't see how it's forbidden.

(Even if the standard defines the argument as a non-const reference that
doesn't mean operator<< *has* to modify its argument.)
Imagine if stdout were the actual stream object rather than a
pointer-to-object. In that case, you would need to write:

fprintf(&stdout, ...);

That depends on how the stream object is implemented.
Likewise, without references, the C++ version would need to be this to
get pass-by-pointer semantics:

*cout << ...;

Perhaps the example would be cleaner if we looked at operator+=(), which
obviously must modify its first (non-const reference) argument?

I'm not arguing that C++ overloaded operators can't modify their
arguments, just that operator<< doesn't absolutely have to do so.
 
R

Rosario1903

On 22-May-13 02:55, Rosario1903 wrote:
one would not use the useless word "const"... it is enough one
has the formal programming law that arg value for function as in
f(a,b,c) not modify a, b c just after the call if their
definition [a,b,c] is not type pointer

for modify that value their have to be pointers not values or
reference. e.g int a; f(&a, b) so the value that contain a can
be changed

if g(int& a, b)
int a; g(a,b)

than a is not changed..

The way C++ does operator overloading requires that functions be
able to modify (non-const) reference arguments.

but i not modify them as a law for write code

Consider this basic snippet:

cin << "Hello World!" << endl;

That calls operator<<() twice, and in both cases, the function modifies
its first reference argument (cin); it cannot work any other way.
Granted, you may not take advantage of that feature of the language for
your own functions, but you're probably missing out on opportunities to
write more efficiently and clearly when that's the best solution.

yes for operators we use reference
but my speach it is for C-like functions

for example if f() modify "cin" i would write:
f(&cin, "hello")
using pointers and not
f(cin, "hello")
where cin is a reference for f
Sorry; I don't understand what you're saying here.

if the compiler see i use one variable as a constant, see all the code
not change it: the compiler can optimize it for that use
Pass-by-reference and pass-by-pointer are no different in that way.

yes
but in C++, in C like functions, when i pass something to them
i have the programming law:

when i write f(a,b,c)
where a,b,c are one type, can be reference too, than a, b, c can not
be changed from f

when i write f(&a, b, &c)
than b not change even if it is a reference, but a and b can be
changed from f

in few words, text as this
<> int original;
<> int& reference = original;
it is not so useful.

where can be useful it is in show when i read a function if it chage
its arg value eg

int f(int* a, int& b, int c);

it change what a point not b not c
if i use in
int a,b,c;
f(&a, b, c);
i know f() can change only what "a" point, not "b", not "c"

this is for the law programming i would follow
even if "b" can be changed from f...
 
G

gwowen

If foo() takes a non-const reference argument, it could change i in the
caller;

I don't think anyone would advocate passing non-class types by
reference, const or otherwise.

struct matrix m = generate_huge_non_singular_matrix();
invert_in_place(m);

I think that's a perfectly comprehensible piece of code.
a C programmer would only expect that to be possible if the call
looked like this:

What if it looked like this?

// C++ code
int i = 5;
increment_by_seven(i);

Not good form, but I suspect even a C programmer may be able to deduce
what's going on.

Besides, the C programmers expectation breaks pretty easily:
/* C code */
#include "my_type.h"

void frobnicate(my_type foo);

int fooble(my_type foo)
{
frobnicate(foo);
/*
* Has foo been mutated? Well, that all depends on the typedef
* (which could be an array, a pointer or even an opaque type)
*/
}
 
G

gwowen

when i write f(a,b,c)
where a,b,c are one type, can be reference too, than a, b, c can not
be changed from f

.... unless they're arrays, or typedefs of arrays, or unless one of the
variables is a pointer that aliases another of the variables, or
unless one of the variables is aliased by some pointer with global or
file scope.
 
M

Malcolm McLean

Besides, the C programmers expectation breaks pretty easily:

/* C code */

#include "my_type.h"



void frobnicate(my_type foo);



int fooble(my_type foo)

{

frobnicate(foo);

/*

* Has foo been mutated? Well, that all depends on the typedef

* (which could be an array, a pointer or even an opaque type)

*/

}
typedef allows you to hide the fact that a type is a pointer, which is
almost always a bad idea, but hard to make illegal because there are
a few cases where abstracting out the fact that you sometimes need
a pointer and sometimes don't is legitimate.
Unfortunately some styles demand that programmers routinely typedef
pointer types. So it's hard to know if objects are modified or not.
You can use const to qualify a pointer, but except for string types
it's rarely much help to the programmer, because it either obvious
from the function description

void normalize(float *v)

or it's none of you business

void engage_warp_drives(DILITHIUM *crystal_interface)
 
R

roland.arthaud

Well, to me at some point "this does change / does not change" thing is more a matter of contract and ultimately belongs to documentation, as the C/C++ syntax has hard time specifying a definite mutability ("depth") of an object.
 
M

Malcolm McLean

Well, to me at some point "this does change / does not change" thing is more a
matter of contract and ultimately belongs to documentation, as the C/C++ syntax > has hard time specifying a definite mutability ("depth") of an object.
Pointers can alias, and there's no sensible way of having a variable length
element without using a pointer.
So it's impossible to specify at the syntax level whether an object "owns" a
variable length filed or just has a reference to it.
 
R

Rosario1903

... unless they're arrays, or typedefs of arrays, or unless one of the
variables is a pointer that aliases another of the variables, or
unless one of the variables is aliased by some pointer with global or
file scope.

yes if they are pointers or array , but they modify not itself but the
mem they point to...
 
S

Seebs

Let's say I ask a primary school child to count out 42
beans, and he does it correctly. This is not sufficient to
be called "arithmetic". It's knowing the numbers, or "counting on".

I have never seen this usage before. I assume this is the sense of "on"
as in "moving on" or "continuing on"? I am aware of that sense of the
preposition, but I've never seen it use in conjunction with "counting"
simply because "counting on" is already a defined term, equivalent to
"relying on" or possibly "taking for granted".

In any event, the term "pointer arithmetic" includes even the trivial
cases. The operator + is an arithmetic operator in C, whether or not the
resulting operation is trivial. We don't generally argue that "x = x + 1"
is not-arithmetic, but "x = x + 23" is, or anything like that. It's all
arithmetic.

-s
 
S

Seebs

I'm not sure I've ever deliberately used the unary + operator, so it's
not surprising that I've forgotten what the constraints are - but I
should have checked before posting.

I would be pretty confident that there existed some time within the last
two decades when I could have told you from memory that C had a unary +
operator, but I couldn't have five minutes ago.

-s
 
M

Malcolm McLean

I have never seen this usage before. I assume this is the sense of "on"
as in "moving on" or "continuing on"? I am aware of that sense of the
preposition, but I've never seen it use in conjunction with "counting"
simply because "counting on" is already a defined term, equivalent to
"relying on" or possibly "taking for granted".

In any event, the term "pointer arithmetic" includes even the trivial
cases. The operator + is an arithmetic operator in C, whether or not the
resulting operation is trivial. We don't generally argue that "x = x + 1"
is not-arithmetic, but "x = x + 23" is, or anything like that. It's all
arithmetic.
"Counting on" simply means that you count up to, say, a hundred, or
start from a hundred, then go "one hundred and one", "one hundred and
two" and so on.
Its a semantic argument whether we call it "arithmetic" or not, but
generally we don't. That's because most people are able to count low
integers at least as a function of knowing the names of the numbers
in their native language. But they can't add two integers unless
they've had at least a few terms of primary school. What they can do
is count until told to stop, so if they've got a counter (e.g. beans
in a bucket) they can do what constitutes addition.
If you want to understand this in a more computer science sort of
way, multiplication is repeated addition, and exponentiation is
repeated multiplication. So what operation is below addition in the
list? Operation zero is "a plus count of as". So using a dot for op
zero, 3.3.3.3 = 7 = 3 + 4. Iterated operation zero is addition. To
implement op zero, you start at the first number and count the number
of times it appears in the list. So operation zero is "counting on".

It's one degree of recursion simpler than addition.

Array notation you can understand purely in terms of op zero. You
don't need to abstract it to addition. We tend to do this because
we're so familiar with addition. But really array[42] isn't
"take array, add 42, find the value and dereference it", it's
"take array and count on 42 places".
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top