Constant strings

K

Keith Thompson

BartC said:
James Kuyper said:
No, that doesn't help. Without a specific consequence that follows from
an array being const, that wouldn't follow from it's elements being
const (or vice versa), it's just words being rearranged in pleasing
patterns.

I've given at least one possible example elsewhere.

Where A is 'const int A[]', then A as an expression as type 'pointer to
const int' while &A as an expression has type 'pointer to array of const
int'.

Yes, A is an array of const int.
This was sufficient to give a different diagnostic (when being passed as a
void* parameter) on one well-known compiler. Not an official difference, but
different behaviour nonetheless.

Sorry, I'm confused. We're talking about the difference between an
array of const int and a (hypothetical) const array of int. There is no
const array of int in your example. What "different diagnostic" are you
referring to?

[...]
 
B

BartC

Keith Thompson said:
Sorry, I'm confused. We're talking about the difference between an
array of const int and a (hypothetical) const array of int. There is no
const array of int in your example. What "different diagnostic" are you
referring to?

I don't know how to do message links. This refers to my post in this thread,
a reply to James Kuyper, dated 26-Apr-14 12:27 (GMT+1), and a follow-up
(reply to Ben Bacarisse) at 13:50 GMT+1.

To summarise, with standard gcc options, the compiler generated a warning
when passing this array:

const int A[3];

as the first parameter of memset(), when using A (pointer to const int), but
not when using &A (pointer to array of const int). I suggested that a
hypothetical 'pointer to const array of int' type here, would have helped it
detect the use of a pointer to a read-only location (and therefore behave
differently compared with 'pointer to array of const int).
 
I

Ian Zimmerman

Just in case I'm not the only one having trouble with the word
"extensional", I'll quote a definition from Wikipedia.

Wikipedia isn't as clear as it could be on this point. The best example
I have seen was, I think, in some book by W. V. O. Quine, though he
might have cribbed it from somewhere:

Is there a difference between the morning star and the evening star?

Answer: extensionally, there isn't. Intensionally, there is.

--
Please *no* private copies of mailing list or newsgroup messages.

gpg public key: 2048R/984A8AE4
fingerprint: 7953 ADA1 0E8E AB57 FB79 FFD2 360A 88B2 984A 8AE4
Funny pic: http://bit.ly/ZNE2MX
 
S

Stephen Sprunk

Of course you can pass an array ... the fact its not copied is
neither here nor there.

You can try to pass an array, but in fact it decays to a pointer.
A pointer to the first element of the array is "the array".....

Try telling that to sizeof.

S
 
K

Keith Thompson

BartC said:
Keith Thompson said:
Sorry, I'm confused. We're talking about the difference between an
array of const int and a (hypothetical) const array of int. There is no
const array of int in your example. What "different diagnostic" are you
referring to?

I don't know how to do message links. This refers to my post in this thread,
a reply to James Kuyper, dated 26-Apr-14 12:27 (GMT+1), and a follow-up
(reply to Ben Bacarisse) at 13:50 GMT+1.

To summarise, with standard gcc options, the compiler generated a warning
when passing this array:

const int A[3];

as the first parameter of memset(), when using A (pointer to const int), but
not when using &A (pointer to array of const int). I suggested that a
hypothetical 'pointer to const array of int' type here, would have helped it
detect the use of a pointer to a read-only location (and therefore behave
differently compared with 'pointer to array of const int).

Interesting.

This program:

#include <string.h>
#include <stdio.h>
int main(void) {
const int arr[10] = { 0 };
memset(&arr, 0xff, sizeof arr);
printf("arr[0] = %d\n", arr[0]);
}

produces no warnings with gcc 4.9.0 (the latest version), but with clang
3.4:

clang -std=c11 -pedantic -Wall -Wextra -O3 c.c -o c

I get:

c.c:4:12: warning: passing 'const int (*)[10]' to parameter of type 'void *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
memset(&arr, 0xff, sizeof arr);
^~~~
/usr/include/string.h:65:28: note: passing argument to parameter '__s' here
extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1));
^
1 warning generated.

It appears to me that gcc follows the letter of the standard, and clang
follows its intent.

The rules for argument passing and initialization are the same as for
simple assignment, at least for cases like this. N1570 6.5.16.1 says:

One of the following shall hold:
[...]
- the left operand has atomic, qualified, or unqualified pointer
type, and (considering the type the left operand would have after
lvalue conversion) one operand is a pointer to an object type, and
the other is a pointer to a qualified or unqualified version of
void, and the type pointed to by the left has all the qualifiers
of the type pointed to by the right;
[...]

The previous bullet, which I haven't quoted, applies when the left and
right operands point to compatible types rather than one of them
pointing to void.

If I'm understanding this correctly (and I'm not at all confident of
that), the solution would not be to create a distinction between array
of const FOO and const array of FOO, but to fix 6.5.16.1 so that the
qualifiers of an array's element type are considered rather than just
the qualifiers of the array type itself (and recursively for arrays of
arrays).
 
G

glen herrmannsfeldt

(snip)
You can try to pass an array, but in fact it decays to a pointer.

Unless it is inside a struct, in which case it can be passed by
value, along with the rest of the struct.

Passing a pointer by value isn't much different, other than name,
from pass by reference.

-- glen
 
B

Ben Bacarisse

glen herrmannsfeldt said:
Passing a pointer by value isn't much different, other than name,
from pass by reference.

I suppose it depends on what you are used to. In the "olden days" (the
70 and 80) when reading the reference manual for one of the seemingly
thousands of new programming languages that were popping up at the time,
if I read the phrase "arguments are passed by reference" or was told
that some syntax caused a argument to be "passed by reference", I would
assume that I need do nothing special in either the call or the function
body to get this effect. In C, I must arrange for the pointer to
passed, and I must pepper the function body with *s to refer to the
referenced object.
 
J

James Kuyper

I think I've seen you argue for things that have no semantic
consequences, such as expression order in equality tests, but the upshot

Yes, I have, though in that particular case I argued for an order that
does a better job of producing error messages when certain common types
of mistakes are made. I'm not clear whether that counts as an
extensional or intensional distinction - I do, however, consider it a
practically useful one. On the flip side, while I presented an argument
for that order, I've seldom actually used that order - in this case, the
benefits to be too weak to even convince myself.

A better example, and one that is closely related to this thread, is the
fact that I follow a convention of using T* for function parameters that
point to a single object, and T[] for function parameters that point at
the first of a series of objects that are (or at least, might be)
accessed by the function, even though there's not a single feature of C
that cares about that distinction.

I've never argued that such concerns were a strong argument for any
particular coding style.
is that there are two separate cases to be made: do the two notions
differ in any way that is detectable within C, and are there any other
reasons why the distinction might matter?

In C as it's currently written, there is no way to even use one of the
two notions, much less identify a meaningful distinction between them.
As Seungbeom Kim has already pointed out, 6.7.3p9 says "If the
specification of an array type includes any type qualifiers, the element
type is so-qualified, not the array type."

The suggestion that was made was that an opportunity had been missed to
make the C type system more consistent, which means it must be talking
about a modified version of C. It must, at a minimum, be modified by
removing section 6.7.3p9. But on top of that, I don't see it as much of
a missed opportunity, unless that modified version of C also differed
from current standard C by making the distinction matter for some
reason. What I've been trying to identify is what people who feel this
way think the distinction should be.
 
B

BartC

Ben Bacarisse said:
I suppose it depends on what you are used to. In the "olden days" (the
70 and 80) when reading the reference manual for one of the seemingly
thousands of new programming languages that were popping up at the time,
if I read the phrase "arguments are passed by reference" or was told
that some syntax caused a argument to be "passed by reference", I would
assume that I need do nothing special in either the call or the function
body to get this effect. In C, I must arrange for the pointer to
passed, and I must pepper the function body with *s to refer to the
referenced object.

With function names and arrays, these are effectively passed by reference in
C without needing to use & in the caller or * in the callee (when using ()
or [] operators).
 
B

Ben Bacarisse

BartC said:
Ben Bacarisse said:
I suppose it depends on what you are used to. In the "olden days" (the
70 and 80) when reading the reference manual for one of the seemingly
thousands of new programming languages that were popping up at the time,
if I read the phrase "arguments are passed by reference" or was told
that some syntax caused a argument to be "passed by reference", I would
assume that I need do nothing special in either the call or the function
body to get this effect. In C, I must arrange for the pointer to
passed, and I must pepper the function body with *s to refer to the
referenced object.

With function names and arrays, these are effectively passed by
reference in C without needing to use & in the caller or * in the
callee (when using () or [] operators).

Yes, but you get to chose how you talk about this particular case. Does
C have pass by reference in some very limited situations (where we
pretend that () is not an operator on function pointers, and that [] is
not a shorthand for * with arithmetic) or do you say that C has a
single, simple, method of passing arguments but that it has special
rules for arrays and function that apply in lots of other situations,
not just in function calls?
 
G

glen herrmannsfeldt

I suppose it depends on what you are used to. In the "olden days" (the
70 and 80) when reading the reference manual for one of the seemingly
thousands of new programming languages that were popping up at the time,
if I read the phrase "arguments are passed by reference" or was told
that some syntax caused a argument to be "passed by reference", I would
assume that I need do nothing special in either the call or the function
body to get this effect. In C, I must arrange for the pointer to
passed, and I must pepper the function body with *s to refer to the
referenced object.

For arrays, C makes it look pretty close, especially if you
declare s[] instead of *s. (And as long as you don't change s.)

For scalars, yes, you put *s all over. Is there a better way?

You have to have some way to distinguish pointer and pointee.

For PL/I, you give them different names. Maybe not so bad.

Fortran has a different assignment operator to assign a pointer
value. A little less convenient, as you can't access the pointer
value in all contexts.

In Java, you dereference a reference object variable with either
the [] or . operator, where . acts more like C's -> operator.
Objects are always described using object references, so there
is no need for something like the C . operator.

If I really get tired of writing *s all over,

#define S (*s)

fixes it.

-- glen
 
B

BartC

glen herrmannsfeldt said:
I suppose it depends on what you are used to. In the "olden days" (the
70 and 80) when reading the reference manual for one of the seemingly
thousands of new programming languages that were popping up at the time,
if I read the phrase "arguments are passed by reference" or was told
that some syntax caused a argument to be "passed by reference", I would
assume that I need do nothing special in either the call or the function
body to get this effect. In C, I must arrange for the pointer to
passed, and I must pepper the function body with *s to refer to the
referenced object.

For arrays, C makes it look pretty close, especially if you
declare s[] instead of *s. (And as long as you don't change s.)

For scalars, yes, you put *s all over. Is there a better way?

[Warning: the following statements are about a private language which is not
C and for which no formal spec exists online **]

One language of mine allows parameters to be marked as being by reference (I
use a & prefix on the formal parameter). This has the affect of
automatically causing & to be placed in front of any arguments, and
automatically dereferencing the parameter in the body of the function. It
seems to work well (although I haven't yet tried it on a static-typed C-like
language).

(Another, older method, that /was/ used for a static language, was to have a
pointer attribute to automatically dereference it. In the argot it used,
'ref int' was a normal pointer to int, while 'ref. int' was a pointer that
would always deference - up to the dot position. I can't remember if this
also took care of function arguments or not.)

[/warning]

Doubtless there must be plenty of other ways of doing the same in other
languages.

.... Or do you mean a better way in C?
If I really get tired of writing *s all over,

#define S (*s)

fixes it.

Ie. a kludge (as a lot of these things are when using macros to fix language
short-comings).
 
B

Ben Bacarisse

glen herrmannsfeldt said:
I suppose it depends on what you are used to. In the "olden days" (the
70 and 80) when reading the reference manual for one of the seemingly
thousands of new programming languages that were popping up at the time,
if I read the phrase "arguments are passed by reference" or was told
that some syntax caused a argument to be "passed by reference", I would
assume that I need do nothing special in either the call or the function
body to get this effect. In C, I must arrange for the pointer to
passed, and I must pepper the function body with *s to refer to the
referenced object.

For arrays, C makes it look pretty close, especially if you
declare s[] instead of *s. (And as long as you don't change s.)

See my reply to BartC: calling this pass by reference just complicates
the description of a language that has enough special cases already!
For scalars, yes, you put *s all over. Is there a better way?

Better in what sense? Languages that actually have pass by reference
make it simpler, but the whole idea is in disrepute, so you might be
asking about ways to make a bad thing badder.
You have to have some way to distinguish pointer and pointee.

Yup. That's one reason why passing a pointer is not pass by reference.
In the "olden days" it had a relatively clear meaning: it meant that an
assignment to a parameter altered the argument in the caller. Because
modern languages don't have pass by reference, I forget that I should
probably say more clearly what it is. Some readers will never have used
a language that has it (I know you have).

Because passing a reference (or a pointer) and pass by reference sound a
bit similar, the meanings have got all tangled up.

<snip>
 
G

glen herrmannsfeldt

With function names and arrays, these are effectively passed by reference in
C without needing to use & in the caller or * in the callee (when using ()
or [] operators).

As long as you don't change the pointer in the called routine.

-- glen
 
B

BartC

Ben Bacarisse said:
glen herrmannsfeldt said:
Ben Bacarisse said:
Passing a pointer by value isn't much different, other than name,
from pass by reference.
I suppose it depends on what you are used to. In the "olden days" (the
70 and 80) when reading the reference manual for one of the seemingly
thousands of new programming languages that were popping up at the time,
if I read the phrase "arguments are passed by reference" or was told
that some syntax caused a argument to be "passed by reference", I would
assume that I need do nothing special in either the call or the function
body to get this effect. In C, I must arrange for the pointer to
passed, and I must pepper the function body with *s to refer to the
referenced object.

For arrays, C makes it look pretty close, especially if you
declare s[] instead of *s. (And as long as you don't change s.)

See my reply to BartC: calling this pass by reference just complicates
the description of a language that has enough special cases already!
For scalars, yes, you put *s all over. Is there a better way?

Better in what sense? Languages that actually have pass by reference
make it simpler, but the whole idea is in disrepute, so you might be
asking about ways to make a bad thing badder.

If we're talking about C, then it doesn't /have/ formal pass-by-reference,
but it /uses/ pass-by-reference extensively through explicit use of
pointers.

In which case he might mean a better way of doing the latter.

As for being in disrepute, it seems unlikely to me that modern languages are
all embracing pass-by-value exclusively. They will use pass-by-reference or
equivalent behind the scenes, because it's more efficient for non-primitive
types, but they might also introduce restrictions such as immutability to
avoid this causing too many unexpected problems.
 
G

glen herrmannsfeldt

(snip, someone wrote)
With function names and arrays, these are effectively passed by
reference in C without needing to use & in the caller or * in the
callee (when using () or [] operators).
Yes, but you get to chose how you talk about this particular case.
Does C have pass by reference in some very limited situations (where we
pretend that () is not an operator on function pointers, and that [] is
not a shorthand for * with arithmetic) or do you say that C has a
single, simple, method of passing arguments but that it has special
rules for arrays and function that apply in lots of other situations,
not just in function calls?

As in the previous post, as long as you don't change the pointer, the
effect is as it would be with call by reference. But only with call
by value can you change the reference in the called routine.

int f(int x[]) {
int a[10];
x[3]=3;
x=a;
x[3]=3;
return x[3];
}

or something similar with function pointers.

-- glen
 
B

Ben Bacarisse

BartC said:
Ben Bacarisse said:
glen herrmannsfeldt said:
<snip, I wrote>
Passing a pointer by value isn't much different, other than name,
from pass by reference.

I suppose it depends on what you are used to. In the "olden days" (the
70 and 80) when reading the reference manual for one of the seemingly
thousands of new programming languages that were popping up at the time,
if I read the phrase "arguments are passed by reference" or was told
that some syntax caused a argument to be "passed by reference", I would
assume that I need do nothing special in either the call or the function
body to get this effect. In C, I must arrange for the pointer to
passed, and I must pepper the function body with *s to refer to the
referenced object.

For arrays, C makes it look pretty close, especially if you
declare s[] instead of *s. (And as long as you don't change s.)

See my reply to BartC: calling this pass by reference just complicates
the description of a language that has enough special cases already!
For scalars, yes, you put *s all over. Is there a better way?

Better in what sense? Languages that actually have pass by reference
make it simpler, but the whole idea is in disrepute, so you might be
asking about ways to make a bad thing badder.

If we're talking about C, then it doesn't /have/ formal pass-by-reference,
but it /uses/ pass-by-reference extensively through explicit use of
pointers.

.... which are passed by value. I think you are keen to use the term
because it suits something about the way you think about programming
languages. For me, borrowing a phrase with a specific meaning ("pass by
reference") and using with a rather vague modifier ("uses") just makes a
mess. Do you object to the simple claim the C does not pass any
function arguments by reference?
 
B

Ben Bacarisse

glen herrmannsfeldt said:
(snip, someone wrote)
With function names and arrays, these are effectively passed by
reference in C without needing to use & in the caller or * in the
callee (when using () or [] operators).
Yes, but you get to chose how you talk about this particular case.
Does C have pass by reference in some very limited situations (where we
pretend that () is not an operator on function pointers, and that [] is
not a shorthand for * with arithmetic) or do you say that C has a
single, simple, method of passing arguments but that it has special
rules for arrays and function that apply in lots of other situations,
not just in function calls?

As in the previous post, as long as you don't change the pointer, the
effect is as it would be with call by reference.

That's a peculiar view. The only way in which arguments passed by
reference differ from the norm is if you change them! You are ruling
out the one thing that makes pass by reference detectable. The fact
that things reachable via the argument can be changed is shared by
languages that have pass by reference and those that don't.

I find all this a little odd. Is there a "freedom to say C has pass by
reference" political party? What's wrong with the simple explanation of
how values are passed from caller to callee?

<snip>
 
M

Malcolm McLean

As for being in disrepute, it seems unlikely to me that modern languages are
all embracing pass-by-value exclusively. They will use pass-by-reference or
equivalent behind the scenes, because it's more efficient for non-primitive
types, but they might also introduce restrictions such as immutability to
avoid this causing too many unexpected problems.
So called closures are getting popular.

This works along the lines of

function foo
{
variable foo_scope =0;

function bar
{
foo_scope = 42;
}

callsomethingthattakesafunction(bar);

/* foo_cope now 42 */
}
 
K

Kaz Kylheku

[Warning: the following statements are about a private language which is not
C and for which no formal spec exists online **]

You wrote a formal spec and expect users to actually read it?

Irony ...
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top