Constant strings

Discussion in 'C Programming' started by BartC, Apr 18, 2014.

  1. Referring to the way C handles arrays in function calls as "pass by
    reference" glosses over the fact that the behavior is based on rules
    that apply to arrays in general. The decay of array expressions
    to pointers has nothing specifically to do with function calls;
    it applies equally to assignment, initialization, array indexing,
    and so forth. The other relevant rule, that an array parameter is
    "adjusted" to a pointer parameter, is specific to functions, but
    I'd call it a kind of syntactic sugar, not something fundamental
    to the semantics of the language as pass-by-reference would be.

    Saying that arrays are "passed by reference" has led too many
    inexperienced C programmers to assume, quite reasonably, that sizeof
    applied to an array parameter should yield the size of the array.

    C has pass-by-reference in the same sense that C has linked lists.
    It provides tools (pointers) from which you can build code that
    has the effect of pass-by-reference, or of linked lists, but it
    has neither as a feature of the language.
     
    Keith Thompson, Apr 28, 2014
    1. Advertisements

  2. Nor does it have "subroutines".

    Which was my point all along.

    Thank you; my work here is done.
     
    Kenny McCormack, Apr 28, 2014
    1. Advertisements

  3. BartC

    Kaz Kylheku Guest

    The right language for that is that arrays are communicated by reference in the
    general sense of any data flow that occurs in the program, not only across
    function boundaries; in other words: that arrays have de-facto reference
    semantics in C.
    No because we can make linked lists in umpteen different, mutually incompatible
    ways in C, the use of any of which can be justified. The conventions for
    passing by reference aren't nearly that numerous.

    There aren't umpteen answers to the question "I have an int variable in this
    scope here, and I want to communicate it into a function such that the function
    can modify the original variable." (There is one right answer, and maybe a
    couple of others contrived just to have the last word in this argument, and
    thus not technically justifiable in the same way that different linked list
    approaches are justifiable.)
     
    Kaz Kylheku, Apr 28, 2014
  4. I can't resist.

    void wrap(int *x, int dim)
    {
    if(*x < 0)
    *x += dim;
    if(* x >= dim)
    *x -= dim;
    }

    #define wrap(x, dim) (x = x < dim ? x + dim : x >= dim ? x - dim : x)
     
    Malcolm McLean, Apr 28, 2014
  5. I was trying to explain in a previous post the difference between
    pass by reference and passing a reference by value. I am not sure
    Bart was convinced.
    In Java, an array reference, passed by value, has a .length
    member which does give the length. You can change array elements,
    or you can change the local copy of the array reference to refer
    to a different array. The latter you normally can't do with
    pass by reference.
    Sounds about right to me.

    -- glen
     
    glen herrmannsfeldt, Apr 28, 2014
  6. BartC

    Kaz Kylheku Guest

    I don't see any real misunderstanding in the above paragraph.
    This is apples and oranges: pointer to element, versus reference to array.

    In C with pointers to array (the "other" way to pass the string by
    reference):

    void ptr2(char (*i)[5])
    {
    }

    int main(void)
    {
    ptr2(&"abcd"); /* okay */
    ptr2(&"abcde"); /* type mismatch */
    return 0;
    }

    Hmm, never address-of on a string literal before. GCC likes it as a C90 compiler
    (with -Wall -W -ansi -pedantic); I can't think of a reason why it wouldn't be
    allowed.
     
    Kaz Kylheku, Apr 28, 2014
  7. BartC

    Ian Collins Guest

    The point was to illustrate passing an array by reference compare to
    what some claim is passing an array by reference (through the pointer to
    it's first element) in C.
    But that isn't really passing by reference as you have to dereference i
    before using it as an array.
     
    Ian Collins, Apr 28, 2014
  8. This isn't pass by reference because an assignment to i, inside ptr2,
    will not alter the object (if there was one) used as an argument in the
    caller!
     
    Ben Bacarisse, Apr 28, 2014
  9. BartC

    Kaz Kylheku Guest

    Since you have to take the address, and dereference the reference this could be
    called "passing by visible reference". If you don't have to then, that is
    "passing by transparent/invisible reference".
     
    Kaz Kylheku, Apr 28, 2014
  10. BartC

    Kaz Kylheku Guest

    Assignment to i resulting in changing a variable in the caller,
    is a feature of "pass by transparent/invisible reference".

    "Pass by explicit/visible reference" requires that a dereferencing
    operator be applied to the reference to designate the caller's object
    from which the reference was obtained.
     
    Kaz Kylheku, Apr 28, 2014
  11. You could also call it "passing a pointer by value". Do you object to
    that way of talking about it? It seems to me less likely to confuse,
    but there appears to be a widely-held view that passing something that
    refers to something else must be called "pass *by* reference" -- despite
    the fact that that phrase used to mean something else.

    If I'm just being an old fogey -- clinging to a usage of language that
    has been superseded -- I'll accept that, but please tell me what the new
    term is for what Fortran does*.

    (* In the absence of the relatively new VALUE attribute.)
     
    Ben Bacarisse, Apr 28, 2014
  12. BartC

    BartC Guest

    Good idea; just spent 30 minutes implementing the closest I have to
    pass-by-reference on one of my static language compilers, so I can compare
    what it does with your example.
    BTW your gratuitous use of 'const' is confusing matters here. (I've spent
    half the thread saying that, but no-one believes me.)
    Wasn't too sure either about the significance of the [5]; I expected ptr()
    to work because it's passing by value (of the pointer to the string); and
    ref() to fail (because it's passing by reference), although I don't know
    what C++ does with constant strings).

    What I think you're saying is that some obscure consequence of how
    pass-by-reference works in C++ allows you to type-check a pointer to an
    array. If you're implying that I don't understand that, then you're right!

    I've done some tests in my own language, and the use of by-reference there
    is far more straightforward and consistent. Use & on a formal parameter, and
    you'd better pass it an l-value expression. A string constant isn't such an
    expression.

    So I understand how *I* want by-reference parameters to work, which might
    have been be a good way of adding them to C. By-value parameter passing in
    C is like this:

    void charlie(double x) {
    x = 23.03;
    }

    int main(void) {
    double a=0.0;
    charlie(a);
    }

    Change that to by-reference by:

    (1) Turn the parameter type into a pointer
    (2) Dereference the parameter in the body of the function
    (3) Use the address-of operator (where needed) with the argument of the
    call.

    Which gives:

    void charlie(double* x) {
    *x = 23.03;
    }

    int main(void) {
    double a=0.0;
    charlie(&a);
    }

    Now charlie() can change the caller's value, which is exactly what we want.
    Except we'd prefer to do it by simply writing:

    void charlie(double &x) {
    x = 23.03;
    }

    int main(void) {
    double a=0.0;
    charlie(a);
    }
     
    BartC, Apr 28, 2014
  13. Did you just make that up or is it now a widely used term? I do like
    to try to keep up if I can.
    No more than any assignment does. Some compilers do indeed generate an
    address and de-reference it, but they don't have to. It is not
    required in all cases. Fortran compilers used to be very good at
    spotting aliasing and (in effect) exchanging the assignment to the
    parameter for an assignment to the argument.
     
    Ben Bacarisse, Apr 28, 2014
  14. BartC

    Kaz Kylheku Guest

    No; I don't object with any multiple non-conflicting views of the same system
    or situation but rather to the denial of any of those views.
     
    Kaz Kylheku, Apr 28, 2014
  15. Exactly. Fortran compilers also don't need to worry about pointer aliasing.
    But whilst its superbly efficient, it's also a lot harder to keep track of
    which variables are being set where, and there's no sort of hierarchy
    or grouping such as structures can impose. So it's less flexible, less
    easy to write programs whose main objective is data manipulation rather
    than calculations.
    You interface Fortran with C by passing pointers, however. A C function
    that is callable from Fortran takes pointers as parameters, a Fortran
    function callable from C is passed pointers.
     
    Malcolm McLean, Apr 28, 2014
  16. BartC

    Kaz Kylheku Guest

    I made it up. I didn't make up "transparent", "invisible" or "reference" of
    course and aren't using them in any non-obvious way.
    Yes; and that is because there actually isn't any special "pass by"
    data flow that is for functions only. Reducing an expression to a value
    and using it to initialize a newly instantiated variable in a new function
    invocation is a data flow. Assignment is another example of a data flow.
    Both of these can be regarded as "passing" something.

    Any time in C a reference to an object moves from one place in the program
    graph to another, we use a value to represent that data flow, and have to
    manually insert operators to source that kind of flow, and to recover the
    referenced value at various "sinks" reached by that value.
     
    Kaz Kylheku, Apr 28, 2014
  17. (snip on call by reference, or not)
    So, the C [] operator is a visible dereference operator, but
    the Fortran () (dummy array subscript) is not?

    But C is different from Fortran in the need for * (or [0])
    on scalar arguments.

    -- glen
     
    glen herrmannsfeldt, Apr 29, 2014
  18. (snip)
    I am not so sure what that means, but Fortran has much stricter
    aliasing rules than C.

    For one, Fortran doesn't require call by reference, but also allows
    for call by value result (also known as copy-in/copy-out).
    The difference is very obvious in some aliasing cases.

    I have known Fortran compilers where the addresses of the arguments
    were passed, and the called routine copied the values in at the
    beginning, and copied them back before returning. On some machines,
    access to local variables is much faster than the indirect addressing
    to access through a reference. Though the actual gain depends on
    how often it is accessed.

    -- glen
     
    glen herrmannsfeldt, Apr 29, 2014
  19. (snip on call by reference and Fortran)
    Actually, Fortran now has the VALUE attribute, and so can also do
    call by value, when needed. It isn't the default, though.

    With the C interoprability feature now in Fortran, you can easily
    call between Fortran and C. If you pass an argument, and don't
    use the VALUE attribute, then a pointer is passed. You can also
    directly pass a TYPE(C_PTR) or the return value of C_LOC() by
    value to a called C function.

    -- glen
     
    glen herrmannsfeldt, Apr 29, 2014
  20. BartC

    Ian Collins Guest

    It isn't gratuitous, it is necessary. C++ had the good sense to make
    string literals what they really are: const.
    There's nothing obscure about it, the type passed to a reference
    parameter has to match. "const char [12]" doesn't match "const char
    [5]". Attempting to pass an object of type char to "void f( int& i )"
    would also fail.
    Exactly. C++ rules for passing by reference are straightforward and
    consistent.
    Which is exactly how C++ does it! You really should look into C++ as
    your base language, it looks to be a much better fit. Yes you can use
    work arounds to make stuff work in C, but those kludges very often cost
    you the ability to perform compile time type checking.
     
    Ian Collins, Apr 29, 2014
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.