On 7/7/24 16:10, BGB wrote:
On 7/7/2024 9:03 AM, James Kuyper wrote:
On 7/7/24 00:55, BGB wrote:
On 7/6/2024 5:38 PM, Keith Thompson wrote:...
...No, there is no implicitly defined pointer.
This implicit pointer need not exist at a location in memory...
Which is why C doesn't give you access to it's location in memory -
something you complained about earlier.
I don't think I was claiming that one should have direct access to its
location or value within the language, rather that their existence and
behaviors could be acknowledged in the language design (for a "not
quite C" language).
I think that the existence of an implicit pointer would be a bad thing
to acknowledge, given that the language doesn't require that it exist,
and typical implementations don't use them. From what I understand, the
fact that your implementation does have implicit pointers makes it a rarity.
On 08/07/2024 19:39, BGB wrote:
On 7/7/2024 11:28 PM, James Kuyper wrote:
On 7/7/24 20:02, Kaz Kylheku wrote:
...
I see no point in having implicit pointers, but I don't believe
that they are prohibited.
They mostly exist in a "sort of simpler to implement the compiler
this way" sense.
In the implicit pointer case, the compiler just treats it as-if it
were an explicit pointer. In this case, both are basically treated
as being roughly equivalent at the IR levels.
And, most of the code-generation stage doesn't need separate
handling for arrays and pointers, but can use combined
"ArrayOrPointer" handling or similar.
It had all seemed "obvious enough".
Similar reasoning for passing structs by-reference in the ABI:
Pass by reference is easy to implement;
In place copying and decomposing into registers, kinda bad.
Though, this one seems to be a common point of divergence between
"SysV" and "Microsoft" ABIs. Sometimes a target will have an ABI
defined, and the MS version was almost the same, just typically
differing in that it passes structs by reference and provides a
spill space for register arguments.
I don't think it is helpful that you keep mixing /logical/ terms with /implementation/ terms.
In C, there is no "pass by reference" or "return by reference". It
is all done by value. Even when you use pointer arguments or return
types, you are passing or returning pointer values. C programmers
use pointers to get the effect of passing by reference, but in C you
use pointers to be explicit about references.
Structs in C are passed by value, and returned by value. Not by
reference.
The C standards don't say how passing structs around by value is to
be implemented - that is hidden from the programmer. Usually ABI's
(which are also hidden from the programmer) specify the
implementation details, but some ABI's are weak in that area.
Generally, structs up to a certain size or complexity are passed in
registers while bigger or more advanced types are passed via
addresses (pointing to stack areas) in registers or the stack, just
like any other bigger types. This is not "pass by reference" as far
as the C programming is concerned - but you could well call it that
at the assembly level. Where the line between "passing in registers"
and "passing via addresses to space on the stack" is drawn, is
entirely up to the compiler implementation and any ABI requirements.
Some simpler compilers will pass all structs via addresses, no matter
how simple they are, while others will aim to use registers whenever possible.
So if you have these structs and declarations :
struct small { uint16_t a; uint16_t b; };
struct big { uint32_t xs[10]; };
struct small foos(struct small y);
struct big foob(struct big y);
Then compilers will typically implement "x = foos(y)" as though it
were:
extern uint32_t foos(uint32_t ab);
uint32_t _1 = foos(y.a << 16) | (y.b);
struct small x = { _1 >> 16, _1 & 0xffff };
And they will typically implement "x = foosb(y)" as though it were:
extern void foob(struct big * ret, const struct big * xs);
struct big x;
foob(&x, &y);
This is not, as you wrote somewhere, something peculiar to MSVC - it
is the technique used by virtually every C compiler, except perhaps
for outdated brain-dead 8-bit microcontrollers that have difficulty
handling data on a stack.
And it is not really "pass by reference" or "implicit pointers", it
is just passing addresses around behind the scenes in the
implementation.
On 06/07/2024 21:33, BGB wrote:
In my compiler (BGBCC), such an internal pointer exists for arrays
and structures in the local stack frame.
No separate pointer exists inside of things like structs, where, as
can be noted, the array exists at a fixed size and location.
So, eg:
void Foo()
{
int a[100];
...
}
There is both the space for 100 integers reserved in the stack
frame, and a variable 'a' which exists as an implicit pointer to
that location.
But, say:
void Foo()
{
int a[8192];
...
}
There is no space reserved on the stack, and the array is instead allocated dynamically (from the heap). In this case, the "a"
variable exists as a pointer to that location in memory.
Similar treatment also applies to structs.
The C standard does not require a stack or say how local data is implemented, it just gives rules for the scope and lifetime of
locals. However, I would be surprised and shocked to find a compiler
I was using allocate local data on the heap in some manner. If I
have an array as local data, it is with the expectation that it is
allocated and freed trivially (an add or subtract to the stack
pointer, typically combined with any other stack frame). If I want
something on the heap, I will use malloc and put it on the heap.
Such an implementation as yours is not, I think, against the C
standards
- but IMHO it is very much against C philosophy.
On Tue, 9 Jul 2024 16:31:30 +0200
David Brown <[email protected]> wrote:
So if you have these structs and declarations :
=20
struct small { uint16_t a; uint16_t b; };
struct big { uint32_t xs[10]; };
=20
struct small foos(struct small y);
struct big foob(struct big y);
=20
Then compilers will typically implement "x =3D foos(y)" as though it
were:
=20
extern uint32_t foos(uint32_t ab);
uint32_t _1 =3D foos(y.a << 16) | (y.b);
struct small x =3D { _1 >> 16, _1 & 0xffff };
=20
And they will typically implement "x =3D foosb(y)" as though it were:
=20
extern void foob(struct big * ret, const struct big * xs);
struct big x;
foob(&x, &y);
It depends on the ABI. Newer ABIs tend to work like that. Older ABIs
often copy the [big] structure to parameters area on callie's stack.
With 16 or more registers I see no obvious performance advantage to
either method. The preference of newer ABIs appears to be a matter of >fashion.
On 09/07/2024 16:58, Ben Bacarisse wrote:
bart <[email protected]> writes:
Arrays are passed by reference:
void F(int a[20]) {}
int main(void) {
int x[20];
F(x);
}
This is the sort of thing that bad tutors say to students so that they
never learn C properly. All parameter passing in C is by value. All of
it. You just have to know (a) what the syntax means and (b) what values
get passed.
The end result is that a parameter declared with value-array syntax is
passed using a reference rather than by value.
And it does so because the language says, not because the ABI requires
it. A 2-byte array is also passed by reference.
On 09/07/2024 23:32, Kaz Kylheku wrote:
On 2024-07-09, bart <[email protected]> wrote:
On 09/07/2024 16:58, Ben Bacarisse wrote:
bart <[email protected]> writes:
Arrays are passed by reference:
void F(int a[20]) {}
int main(void) {
int x[20];
F(x);
}
This is the sort of thing that bad tutors say to students so that they >>>> never learn C properly. All parameter passing in C is by value. All of >>>> it. You just have to know (a) what the syntax means and (b) what values >>>> get passed.
The end result is that a parameter declared with value-array syntax is
passed using a reference rather than by value.
And it does so because the language says, not because the ABI requires
it. A 2-byte array is also passed by reference.
In C, arrays are not passed to functions, period.
Arrays can be passed by explicit reference:
On 7/10/24 00:29, Lawrence D'Oliveiro wrote:
On Sat, 06 Jul 2024 15:38:14 -0700, Keith Thompson wrote:...
If you evaluate the expression `array_object` in most contexts, it's
implicitly converted to a pointer *value*, pointing to the 0th element
of the array object. There is still no implicit pointer object.
The OP said “pointer”, not “pointer object” or “pointer value”. Not sure
what hair you are trying to split here.
BGB referred to it as an "implicitly declared" pointer. You can declare objects in C, but not values. An object has a location in addressable
memory where it is stored, a value need not exist anywhere in
addressable memory.
In every implementation that I'm sufficiently familiar with, no memory
is set aside to store such a pointer object.
On Sat, 06 Jul 2024 15:23:47 -0700, Keith Thompson wrote:
Lawrence D'Oliveiro <[email protected]d> writes:
On Fri, 05 Jul 2024 11:46:38 -0700, Keith Thompson wrote:
No, arrays are not pointers.
Except array indexing is designed to be indistinguishable from pointer
arithmetic.
No, arrays are not pointers.
Can you point out any situation where this construct
&a[b]
might be valid, but this
(a + b)
(with the same declarations of “a” and “b”) might not?
bart <[email protected]> writes:
I earlier asked this:
"So if arrays aren't passed by value in C, and they aren't passed
by reference, then how the hell ARE they passed?!"
They aren't. C allows lots of things to be passed as an argument
to a function: several varieties of numeric values, structs,
unions, and pointers, including both pointers to object types and
pointers to function types. C does not have a way for a function
to take an argument that is either an array or a function. There
is a way to take pointers to those things, but not the things
themselves. Arrays and functions are second-class values in C.
On 10/07/2024 16:48, Tim Rentsch wrote:
bart <[email protected]> writes:
I earlier asked this:
"So if arrays aren't passed by value in C, and they aren't passed
by reference, then how the hell ARE they passed?!"
They aren't. C allows lots of things to be passed as an argument
to a function: several varieties of numeric values, structs,
unions, and pointers, including both pointers to object types and
pointers to function types. C does not have a way for a function
to take an argument that is either an array or a function. There
is a way to take pointers to those things, but not the things
themselves. Arrays and functions are second-class values in C.
That's a good point. It's not just arrays that can't be passed by
value (because the language says so) but also functions (because its
not meaningful).
Yet, although pointers to arrays and function can be passed (without
even doing anything special like using &), you are not allowed to say
that anything is passed by reference in C!
The automatic conversion to a pointer, which is also a feature of
true pass-by-reference, doesn't count.
Not needing an explicit deref inside the callee (another
characteristic of pass-by-reference) doesn't count either.
I'd like to see an example of the language that permits ahead-of-time compilation and has functions as first-class values.
On 10/07/2024 19:14, Michael S wrote:
On Wed, 10 Jul 2024 08:48:05 -0700
Tim Rentsch <[email protected]> wrote:
bart <[email protected]> writes:
I earlier asked this:
"So if arrays aren't passed by value in C, and they aren't passed
by reference, then how the hell ARE they passed?!"
They aren't. C allows lots of things to be passed as an argument
to a function: several varieties of numeric values, structs,
unions, and pointers, including both pointers to object types and
pointers to function types. C does not have a way for a function
to take an argument that is either an array or a function. There
is a way to take pointers to those things, but not the things
themselves. Arrays and functions are second-class values in C.
I'd like to see an example of the language that permits
ahead-of-time compilation and has functions as first-class values.
Haskell is the first the comes to mind for me, but you could pick any compiled functional programming language.
I am by no means a Haskell expert, and I am not at all familiar with
the way the language is compiled. But it is quite clear that it is
an example of a language that has functions as first-class objects,
and which is ahead-of-time compiled. The example below defines an
int-to-int function "doubler", and also a function-to-function
function "doTwice", and a function quadrupler that is defined as the
result of applying the higher-order function doTwice to doubler.
These are all compiled to assembly.
<https://godbolt.org/z/Tb7hGYsdv>
module Example where
doubler :: Int -> Int
doubler x = 2 * x
doTwice :: (Int -> Int) -> (Int -> Int)
doTwice f x = f (f x)
quadrupler = doTwice doubler
shouldBeEighty = quadrupler 20
You can write much the same in C++ using lambdas (which are objects
and can be passed around and returned as such) and templates (which
are needed because the type of lambdas is hidden). Unfortunately,
this also means that the functions don't get individually generated
functions in assembly:
<https://godbolt.org/z/KvPWz3n8z>
auto doubler = [](int x) -> int { return 2 * x; };
auto doTwice = [](auto f) -> auto
{
return [f](int x) -> int { return f(f(x)); };
};
auto quadrupler = doTwice(doubler);
auto shouldBeEiqhty = quadrupler(20);
On 10/07/2024 19:39, Michael S wrote:
On Wed, 10 Jul 2024 18:30:54 +0100
bart <[email protected]> wrote:
On 10/07/2024 16:48, Tim Rentsch wrote:
bart <[email protected]> writes:
I earlier asked this:
"So if arrays aren't passed by value in C, and they aren't passed
by reference, then how the hell ARE they passed?!"
They aren't. C allows lots of things to be passed as an argument
to a function: several varieties of numeric values, structs,
unions, and pointers, including both pointers to object types and
pointers to function types. C does not have a way for a function
to take an argument that is either an array or a function. There
is a way to take pointers to those things, but not the things
themselves. Arrays and functions are second-class values in C.
That's a good point. It's not just arrays that can't be passed by
value (because the language says so) but also functions (because
its not meaningful).
Yet, although pointers to arrays and function can be passed
(without even doing anything special like using &), you are not
allowed to say that anything is passed by reference in C!
The automatic conversion to a pointer, which is also a feature of
true pass-by-reference, doesn't count.
Not needing an explicit deref inside the callee (another
characteristic of pass-by-reference) doesn't count either.
It does not count, because automatic conversion to a pointer is not something that happens only during parameter passing. For arrays, it happens in all contexts except sizeof(). For functions, it happens
in all contexts except function call. Or, may be, including
function call, in this case (but not in case of arrays) it depends
on point of view.
Suppose that was to happen in all contexts, not just for arrays and functions, but for all types.
That means that if A, B, C were numbers, then any call such as F(A,
B, C) would pass the addresses of the numbers rather than their
values.
According to what people have said, C would STILL be a language that
passed thing by value, and never by automatic reference.
Yet in my scenario that now sounds ludicrous.
On 11/07/2024 00:01, Ben Bacarisse wrote:
bart <[email protected]> writes:
On 10/07/2024 14:32, Ben Bacarisse wrote:
I still consider arrays in C to be 'passed' by a
mechanism which is near-indistinguishable from actual
pass-by-reference.
I don't really care how you consider it, but I do care about how you misrepresent the facts in public.
In another post you said that your language has pass by reference,
and we also know you have implemented C. Either you are just very
confused and your language simply has call by value (after all, you
think C has pass by reference), or you know that pass by reference
in your language needs something from the implementation that was
not needed when you implemented C. I can't decide if you are
confused or just lying.
The way it works in my language is very simple (this is what I do
after all):
type T = int
proc F(T x)= # Pass by value
println x.typestr
end
proc G(ref T x)= # Manual pass-by-reference
println x^.typestr
end
proc H(T &x)= # Auto pass-by-reference
println x.typestr
end
proc main=
T a
F(a)
G(&a)
H(a)
end
I've written 3 functions using pass-by-value, pass-by-value emulating pass-by-reference, and actual pass-by-reference.
The G function and the call to G show what the compiler has to add
when it processes function H: address-of ops and derefs. The cost is
a single & in the parameter list to get that convenience.
This programs works just the same if T was changed to an array:
type T = [4]int
(The output is 3 lots of '[4]i64' instead of 3 lots of 'i64'; 'int'
is an alias for int64/i64.)
This is regular and orthogonal, a complete contrast to C even though
both languages supposedly operate at the same level.
The behaviour of F, when written in C, is like my F function when T
is an int (obviously the C won't have '.typestr').
But when T is an array, its behaviour is more like that of my H
function.
So, my remark about arrays in C being passed by reference is
understandable.
On Wed, 10 Jul 2024 21:28:15 +0200
David Brown <[email protected]> wrote:
On 10/07/2024 19:14, Michael S wrote:
On Wed, 10 Jul 2024 08:48:05 -0700
Tim Rentsch <[email protected]> wrote:
bart <[email protected]> writes:
I earlier asked this:
"So if arrays aren't passed by value in C, and they aren't passed
by reference, then how the hell ARE they passed?!"
They aren't. C allows lots of things to be passed as an argument
to a function: several varieties of numeric values, structs,
unions, and pointers, including both pointers to object types and
pointers to function types. C does not have a way for a function
to take an argument that is either an array or a function. There
is a way to take pointers to those things, but not the things
themselves. Arrays and functions are second-class values in C.
I'd like to see an example of the language that permits
ahead-of-time compilation and has functions as first-class values.
Haskell is the first the comes to mind for me, but you could pick any
compiled functional programming language.
I am by no means a Haskell expert, and I am not at all familiar with
the way the language is compiled. But it is quite clear that it is
an example of a language that has functions as first-class objects,
and which is ahead-of-time compiled. The example below defines an
int-to-int function "doubler", and also a function-to-function
function "doTwice", and a function quadrupler that is defined as the
result of applying the higher-order function doTwice to doubler.
These are all compiled to assembly.
<https://godbolt.org/z/Tb7hGYsdv>
module Example where
doubler :: Int -> Int
doubler x = 2 * x
doTwice :: (Int -> Int) -> (Int -> Int)
doTwice f x = f (f x)
quadrupler = doTwice doubler
shouldBeEighty = quadrupler 20
You can write much the same in C++ using lambdas (which are objects
and can be passed around and returned as such) and templates (which
are needed because the type of lambdas is hidden). Unfortunately,
this also means that the functions don't get individually generated
functions in assembly:
<https://godbolt.org/z/KvPWz3n8z>
auto doubler = [](int x) -> int { return 2 * x; };
auto doTwice = [](auto f) -> auto
{
return [f](int x) -> int { return f(f(x)); };
};
auto quadrupler = doTwice(doubler);
auto shouldBeEiqhty = quadrupler(20);
I fail to see a material difference between first class function values
in Haskell and C++ and first class function pointer values in C:
int doubler(int x) {
return x*2;
}
int doTwice(int (*foo)(int), int x) {
return foo(foo(x));
}
int quadrupler(int x) {
return doTwice(doubler, x);
}
I am willing to believe that the difference exists, but your example is
too basic to demonstrate it.
On 2024-07-11, Michael S <[email protected]> wrote:
On Wed, 10 Jul 2024 21:28:15 +0200
David Brown <[email protected]> wrote:
On 10/07/2024 19:14, Michael S wrote:
On Wed, 10 Jul 2024 08:48:05 -0700
Tim Rentsch <[email protected]> wrote:
bart <[email protected]> writes:
I earlier asked this:
"So if arrays aren't passed by value in C, and they aren't
passed by reference, then how the hell ARE they passed?!"
They aren't. C allows lots of things to be passed as an
argument to a function: several varieties of numeric values,
structs, unions, and pointers, including both pointers to
object types and pointers to function types. C does not have a
way for a function to take an argument that is either an array
or a function. There is a way to take pointers to those
things, but not the things themselves. Arrays and functions
are second-class values in C.
I'd like to see an example of the language that permits
ahead-of-time compilation and has functions as first-class
values.
Haskell is the first the comes to mind for me, but you could pick
any compiled functional programming language.
I am by no means a Haskell expert, and I am not at all familiar
with the way the language is compiled. But it is quite clear that
it is an example of a language that has functions as first-class
objects, and which is ahead-of-time compiled. The example below
defines an int-to-int function "doubler", and also a
function-to-function function "doTwice", and a function quadrupler
that is defined as the result of applying the higher-order
function doTwice to doubler. These are all compiled to assembly.
<https://godbolt.org/z/Tb7hGYsdv>
module Example where
doubler :: Int -> Int
doubler x = 2 * x
doTwice :: (Int -> Int) -> (Int -> Int)
doTwice f x = f (f x)
quadrupler = doTwice doubler
shouldBeEighty = quadrupler 20
You can write much the same in C++ using lambdas (which are objects
and can be passed around and returned as such) and templates (which
are needed because the type of lambdas is hidden). Unfortunately,
this also means that the functions don't get individually generated
functions in assembly:
<https://godbolt.org/z/KvPWz3n8z>
auto doubler = [](int x) -> int { return 2 * x; };
auto doTwice = [](auto f) -> auto
{
return [f](int x) -> int { return f(f(x)); };
};
auto quadrupler = doTwice(doubler);
auto shouldBeEiqhty = quadrupler(20);
I fail to see a material difference between first class function
values in Haskell and C++ and first class function pointer values
in C:
int doubler(int x) {
return x*2;
}
int doTwice(int (*foo)(int), int x) {
return foo(foo(x));
}
int quadrupler(int x) {
return doTwice(doubler, x);
}
I am willing to believe that the difference exists, but your
example is too basic to demonstrate it.
First class functions could do something like this:
// multiplier takes a coefficient and returns a pointer to
// function
int (*multiplier(int coefficient))(int) {
// fantasy lambda syntax. Return type int is written after
// parameter list.
return lambda(int x) int {
return coefficient * x;
}
}
int (*doubler)(int) = multiplier(2);
int x = doubler(42); // x becomes 84
Even though the lambda is returned out of multiplier, whose execution terminates, when the returned function is invoked, it can refer to the coefficient, which is captured in a lexical closure.
With a C-like typedef, we can declutter the definition of mutiplier:
typedef int (*int_int_fn)(int);
int_int_fn multiplier(int coefficient) {
return lambda(int x) int {
return coefficient * x;
}
}
With a C-like typedef, we can declutter the definition of mutiplier:
typedef int (*int_int_fn)(int);
int_int_fn multiplier(int coefficient) {
return lambda(int x) int {
return coefficient * x;
}
}
Thank you.
Your example confirms my suspicion that the difference between first
and second class of functions doesn't become material until language
supports closures.
On 11/07/2024 09:54, Michael S wrote:
On Thu, 11 Jul 2024 01:21:52 +0100
bart <[email protected]> wrote:
On 11/07/2024 00:01, Ben Bacarisse wrote:
bart <[email protected]> writes:
On 10/07/2024 14:32, Ben Bacarisse wrote:
I still consider arrays in C to be 'passed' by a
mechanism which is near-indistinguishable from actual
pass-by-reference.
I don't really care how you consider it, but I do care about how
you misrepresent the facts in public.
In another post you said that your language has pass by reference,
and we also know you have implemented C. Either you are just very
confused and your language simply has call by value (after all,
you think C has pass by reference), or you know that pass by
reference in your language needs something from the
implementation that was not needed when you implemented C. I
can't decide if you are confused or just lying.
The way it works in my language is very simple (this is what I do
after all):
type T = int
proc F(T x)= # Pass by value
println x.typestr
end
proc G(ref T x)= # Manual pass-by-reference
println x^.typestr
end
proc H(T &x)= # Auto pass-by-reference
println x.typestr
end
proc main=
T a
F(a)
G(&a)
H(a)
end
I've written 3 functions using pass-by-value, pass-by-value
emulating pass-by-reference, and actual pass-by-reference.
The G function and the call to G show what the compiler has to add
when it processes function H: address-of ops and derefs. The cost
is a single & in the parameter list to get that convenience.
This programs works just the same if T was changed to an array:
type T = [4]int
(The output is 3 lots of '[4]i64' instead of 3 lots of 'i64'; 'int'
is an alias for int64/i64.)
This is regular and orthogonal, a complete contrast to C even
though both languages supposedly operate at the same level.
The behaviour of F, when written in C, is like my F function when T
is an int (obviously the C won't have '.typestr').
But when T is an array, its behaviour is more like that of my H
function.
So, my remark about arrays in C being passed by reference is
understandable.
No, it isn't.
If [in C] it was possible to pass arrays to functions, either by
value or by reference, then callee would know the length of passed
array. As it is, callee does not know it.
The length can be passed in a separate parameter, but then it does
not have to be the same as an original.
That's rather specious. In my language (probably in C too), most
passed arrays are unbounded, allowing the same function to work with
arrays of different sizes.
So that would need a separate Length parameter, even using
by-reference.
In that regard, it's no different from the C: my array by-ref and C's alledged by-ref both cannot determine the array length solely from
the parameter.
(In my language, attempts to get the length yields 0, which makes
sense as the parameter's bounds are zero. In C, it will yield the
size of the pointer.)
But when the array IS bounded, then in C:
typedef byte vector[4];
void F(vector a) {
printf("%zu\n", sizeof(a));
printf("%zu\n", sizeof(vector));
}
The first printf shows 8 (the pointer size); the second shows 4 (the
array size). So it /can/ access the bounds.
On 12.07.2024 08:00, David Brown wrote:
[...]
I can understand when someone new to C gets mixed up about how arrays
work.
I can't understand that if I presume that the person has read any
basic textbook about "C".
It's clearly not by value. It's apparently not by reference. You can't
get away with saying they are not passed, as clearly functions *can*
access array data via parameters.
On 2024-07-12, Janis Papanagnou <[email protected]>
wrote:
On 12.07.2024 08:00, David Brown wrote:
[...]
I can understand when someone new to C gets mixed up about how
arrays work.
I can't understand that if I presume that the person has read any
basic textbook about "C".
Problem is that over the years there have been authors of basic
textbooks about "C" who were also confused by things like this.
For instance, in Herbert Schildt's "C: The Complete Reference",
3rd Ed, page 53, this can be found:
/* Write 6 integers to a disk file. */
void put_rec(int rec[6], FILE *fp)
{
int len;
len = fwrite(rec, sizeof rec, 1, fp);
if(len != 1) printf("write error");
}
Of course, "sizeof rec" is the size of a pointer, not likely
equal to the size of an array of 6 elements.
The intersection of authors who are skillful presenters of material, knowledgeable about C, and motivated to write about it has not been
that large. We could add to that, "write about new C, and motivated
to keep up with ISO C developments and crank out new edititons".
On 12.07.2024 14:42, Michael S wrote:
I don't share your optimistic belief that the term "pass by
reference" is really established. Very few terms in computer
science (science? really?) are established firmly. Except, may be,
in more theoretical branches of it.
I don't know of any "standard" describing that - if that's what you
are aiming at - but I also wouldn't expect an international standard document. And newer sources (specifically including blogs and bots!) certainly may muddy waters.
All my sources since days in University had a consistent semantical description.
Computer Scientists seems not to have been keen to introduce here
own and different terms.
In case you have other, new [to me], or own concrete semantical interpretations of the "call-by-reference" mechanism I'm certainly
interested to hear about.
Especially in the light of alternative facts and "own definitions"
(like Bart's) I suggest otherwise to not spread FUD about that.
The gridlocked discussion is already annoying enough. :-/
Janis
On 13/07/2024 10:39, BGB wrote:
But, as I see it, no real point in arguing this stuff (personally,
I have better stuff to be doing...).
We all do. But this group seems to be about arguing about pointless
stuff and you might come here when you want a respite from proper
work.
However (here I assume you've gone back to Quake but that other
interested parties might be reading this), consider the program below.
That sets up an array and then sums its elements by calling 3
different functions to do the job:
(1) Using normal C pass-by-value
(2) Using C pass-by-value to emulate call-by-reference
(3) Using fantasy true call-by-reference as it might appear if C had
the feature
(I'd hoped C++ would run this, but it didn't even like the middle
function.)
I'm asking people to compare the first and third functions and their
calls, and to see if there's any appreciable difference between them.
There will obviously be a difference in how the A parameter is
declared.
---------------------------------------------
#include <stdio.h>
typedef int T;
int sum_byvalue(T* A, int n) {
int i, sum=0;
for (i=0; i<n; ++i) sum += A[i];
return sum;
}
int sum_bymanualref(T(*A)[], int n) {
int i, sum=0;
for (i=0; i<n; ++i) sum += (*A)[i];
return sum;
}
int sum_bytrueref(T (&A)[], int n) {
int i, sum=0;
for (i=0; i<n; ++i) sum += A[i];
return sum;
}
int main(void) {
enum {N = 10};
T A[N] = {10,20,30,40,50,60,70,80,90,100};
int total=0;
total += sum_byvalue (A, N);
total += sum_bymanualref (&A, N);
total += sum_bytrueref (A, N);
printf("%d\n", total); // would show 1650
}
---------------------------------------------
Find anything? I thought not.
Those findings might suggest that C doesn't need call-by-reference,
not for arrays anyway. Except that at present you can do this:
T x=42;
sum_byvalue(&x, N);
which would not be possible with call-by-reference. Nor with
sum_bymanualref, but apparently nobody wants to be doing with all
that extra, fiddly syntax. Better to be unsafe!
On 15/08/2024 22:36, Tim Rentsch wrote:
I see. So your point is, if we ignore all the ways that the two
modes are different then they are exactly the same.
Brilliant deduction, Dr. Watson.
So your approach is to totally ignore all the ways that the two modes
are identical.
Bart <[email protected]> writes:
On 15/08/2024 15:33, Ben Bacarisse wrote:
Bart <[email protected]> writes:
On 15/08/2024 09:43, Tim Rentsch wrote:
Bart <[email protected]> writes:
Which is why, presumably, you didn't show the differences. YourC call-by-value
call-by-reference =============== =================
at call:
(array argument) F(A) H(A)
(pointer argument) F(p) (disallowed)
My posts were about passing *arrays* and the fact that C's
pass-by-value was remarkably similar to pass-by-reference.
post was all polemic not part of a collegiate discussion of the
similarities and differences.
However your entry for pointers is not correct:No, the entry is correct. H(p) would be (is?) disallowed when H's
parameter is a reference to an array.
Sorry, what language does the right-hand column pertain to? /Any/
language that has call-by-reference, or Tim's hypthetical language?
Tim said that case was "disallowed". You call that an error on his
part. What language did you have in mind that permits such a gross
warping of types? I would describe /any/ language that allowed it as
having a design error.
Or any that could be used to prove him right?
In general there is no reason, in a language with true
call-by-reference, why any parameter type T (which has the form U*,
a pointer to anything), cannot be passed by reference. It doesn't
matter whether U is an array type or not.
I can't unravel this. Take, as a concrete example, C++. You can't
pass a pointer to function that takes an array passed by reference.
You can, of course, pass a pointer by reference, but that is neither
here nor there.
Michael S <[email protected]> writes:
[...]
IMHO, C++ is a particularly bad example.
Yes, C++ has call-by-reference misfeature. But arrays in C++ are
2nd class citizen, same as in C. They can't be assigned and can't be
passed to callee, neither by value nor by reference.
Also, I suspect that if you ask Ken Thompson, he will tell you that
C++ does not really have 'call by reference'. Instead, it has
references as 1st class object, so, naturally, values of references
can be used during 'call by value'.
I have enough of respect to KT to consider that his POV is not a
nonsense.
Is that an attempt at proof by authority?
Not only does Ken Thompson
have very little to do with C++, but you're basing your conclusion on
what you *suspect* he would say.
On 19/08/2024 03:03, Tim Rentsch wrote:
Ben Bacarisse <[email protected]> writes:
David Brown <[email protected]> writes:
On 16/08/2024 12:00, Ben Bacarisse wrote:
David Brown <[email protected]> writes:
On 16/08/2024 02:08, Ben Bacarisse wrote:
Bart <[email protected]> writes:
In general there is no reason, in a language with true
call-by-reference, why any parameter type T (which has the
form U*, a pointer to anything), cannot be passed by
reference. It doesn't matter whether U is an array type or
not.
I can't unravel this. Take, as a concrete example, C++. You
can't pass a pointer to function that takes an array passed by
reference. You can, of course, pass a pointer by reference,
but that is neither here nor there.
In C++, you can't pass arrays as parameters at all - the
language inherited C's handling of arrays. You can, of course,
pass objects of std::array<> type by value or by reference,
just like any other class types.
The best way to think about C++ (in my very non-expert opinion)
is to consider references as values that are passed by, err...,
value. But you seem prepared to accept that some things can be
"passed by reference" in C++.
That seems a subtle distinction - I'll have to think about it a
little. I like your description of arguments being like local
variable initialisation - it makes sense equally well regardless
of whether the parameter is "int", "int*", or "int&". (It's
probably best not to mention the other one in this group...)
So if this:
#include <iostream>
void g(int &i) { std::cout << i << "\n"; }
int main(void)
{
int I{0};
g(I);
}
shows an int object, I, being passed to g, why does this
#include <iostream>
void f(int (&ar)[10]) { std::cout << sizeof ar << "\n"; }
int main(void)
{
int A[10];
f(A);
}
not show an array, A, being passed to f?
That's backwards compatibility with C array handling at play.
I'm not sure how this answers my question. Maybe you weren't
answering it and were just making a remark...
My guess is he didn't understand the question. The code shown
has nothing to do with backwards compatibility with C array
handling.
I had intended to make a brief remark and thought that was all that
was needed to answer the question. But having thought about it a bit
more (prompted by these last two posts), and tested the code (on the assumption that the gcc writers know the details better than I do),
you are correct - I did misunderstand the question. I was wrong in
how I thought array reference parameters worked in C++, and the way
Ben worded the question re-enforced that misunderstanding.
I interpreted his question as saying that the code "f" does not show
an array type being passed by reference, with the implication that
the "sizeof" showed the size of a pointer, not the size of an array
of 10 ints, and asking why C++ was defined that way. The answer, as
I saw it, was that C++ made reference parameters to arrays work much
like pointer parameters to arrays, and those work like in C for
backwards compatibility.
Of course, it turns out I was completely wrong about how array type
reference parameters work in C++. It's not something I have had use
for in my own C++ programming or something I have come across in
other code that I can remember, and I had made incorrect assumptions
about it. Now that I corrected that, it all makes a lot more sense.
And so I presume Ben was actually asking why I /thought/ this was not
passing an array type (thus with its full type information, including
its size). Then answer there is now obvious - I thought that because
I had jumped to incorrect conclusions about array reference
parameters in C++.
So thank you (Ben and Tim) for pushing me to correct my C++
misunderstanding here, and apologies to anyone confused by my mistake.
| Sysop: | Keyop |
|---|---|
| Location: | Huddersfield, West Yorkshire, UK |
| Users: | 715 |
| Nodes: | 16 (2 / 14) |
| Uptime: | 153:23:28 |
| Calls: | 12,091 |
| Calls today: | 4 |
| Files: | 15,000 |
| Messages: | 6,517,667 |