strange warning

Discussion in 'C Programming' started by Bill Cunningham, May 10, 2014.

  1. int x[5] + { 1, 2, 3, 4, 5 };

    declares an array of 5 integers. Everyone from any programming background
    whatsoever would quickly understand that.
    We can get the number of integers by in the array with the sizeof() operator.
    But very few people would do that. If the x is in scope, the 5 is in the same
    line, and you might as well use it directly, #defining it if you don't
    like magic numbers.
    Then fixed size arrays aren't all that useful. Most real algorithms work
    on variable length arrays. C doesn't tie the length to the buffer,
    the programmer has to keep track of it in the program logic flow.
    So in that sense, C doesn't have arrays, it doesn't have a tight distinction
    between an array and a buffer.
     
    Malcolm McLean, May 10, 2014
    #21
    1. Advertisements

  2. I'm still not at all sure what distinction you're making, or how you
    think that distinction should be expressed in the language syntax.

    The way C handles arrays, pointers, and so forth is not exactly clean,
    but it's incredibly flexible.

    I have no doubt that there are cleaner ways to do this than what C has
    evolved into over the years -- and if you can describe such a way in
    concrete terms, that could be interesting. If you can come up with
    something that could be cleanly added to C without breaking existing
    code, that would be fascinating.


    Strictly speaking, a multidimensional array is nothing more or less than
    an array of arrays. But C provides multiple ways to implement data
    structures that act like multidimensional arrays.

    Is that a problem? If so, how would you solve it?
    Yes, a pointer to one type is really is distinct from a pointer to
    another type, and it's absurd to claim otherwise. Can you clarify the
    point you're trying to make about accessing the data elements?
     
    Keith Thompson, May 10, 2014
    #22
    1. Advertisements

  3. That sounds like you are about to disagree, but...
    .... you then say pretty much what I did, only in a rather confused way.
    (C does not have them (as you understand them) but it has them if we
    qualify the term). My "second class" (a technical term) and my "with
    some rather peculiar rules" are just more expansive versions of your
    less helpful qualification: "C".

    But, yes, let's agree that C has C arrays: that int a[4]; declares a C
    array and that int (*ap)[4]; makes ap a pointer to a C array. And,
    since this is comp.lang.c, we could also agree to drop "C" and take it
    as read.
    Eh? Fortran has Fortran Arrays, Python has Python arrays, Perl as Perl
    arrays... and C has C arrays. All really are instances of the larger
    class of arrays, unless you make a case for the differences being such
    as to exclude them from the class (in which case, you should not really
    use even a qualified name for them).
     
    Ben Bacarisse, May 10, 2014
    #23
  4. (snip)
    (snip, then I wrote)
    I am not sure I can say it all that much better, but consider
    that array a can be referenced as a, and pointer p can be
    referenced as p, so the assignment p=a makes more sense than
    the assignment p=&a;

    Even though it isn't quite right, especially in the case of sizeof,
    I think of a as a pointer to int constant, and so should not use &.

    -- glen
     
    glen herrmannsfeldt, May 10, 2014
    #24
  5. Nonsense.

    The standard defines the language. If you refuse to understand
    what it says, there's not much else to say, other than to wonder
    what you're doing here.

    You can probably do some amount of C programming without
    understanding how C pointers an arrays work, but I doubt that you
    can get very far.

    I won't bother to explain again how C arrays work. If you're
    interested, I recommend section 6 of the comp.lang.c FAQ,
    <http://www.c-faq.com/>. If you're not, that's fine, but you might
    consider leaving this discussion to those of us who are interested.

    [...]
    Standards almost always use English words with meanings that are
    more precise than, and sometimes not entirely consistent with, the
    way they're used in English. The alternative would be to invent
    new words for specific concepts, but I think that would just make
    it more difficult to understand. Do you have a better way to define
    a programming language?
     
    Keith Thompson, May 10, 2014
    #25
  6. (snip)
    I like the way Java multidimensional arrays work.

    You can say:

    int x[][]; (or int[][] x), and then

    x=new int[10][10];

    At which point it allocates a 10 element array of arrays,
    and then 10 arrays of int. The confusion that C has with

    int y[10][10], z[20][20];

    passed to a function, doesn't occur in Java.

    It is fairly rare, but you can separately allocate the arrays
    in Java:

    x=new int[10][];
    x[3]=new int[13];

    and make the subarrays different length.

    -- glen
     
    glen herrmannsfeldt, May 10, 2014
    #26
  7. Bill Cunningham

    Ian Collins Guest



    Just let a compiler provide the explanation:

    c99 b.c
    "b.c", line 7: warning: assignment type mismatch:
    pointer to int "=" pointer to array[5] of int
     
    Ian Collins, May 10, 2014
    #27
  8. People do that all the time:

    #define ARRAY_LENGTH(arr) (sizeof (arr) / sizeof (arr)[0])
     
    Keith Thompson, May 10, 2014
    #28
  9. Two types are compatible if there is an implicit conversion from one
    to the other. For example, from int to long, long to int, int to
    double, pointer to void to any other pointer type.

    Two types are incompatible if the implicit conversion does not exist.
    In your case, the type of p is pointer to int and the type of &a is
    pointer to array of 5 int. There is no implicit conversion between
    these types..
    The type of a pointer variable is never int. It is always pointer to
    something. In your case, p has type pointer to int.
    The meaning of a[] is context dependent.

    In a definition such as
    int a[] = {1,2,3,4,5};
    it means a is an array whose number of elements will be determined by
    the number of initializers provided.

    In a function declaration such as
    void func(int a[]);
    it means that the parameter a received from the calling function is in
    fact a pointer to int and the function declaration is exactly
    equivalent to
    void func(int *a);

    Since expression a[] never appears in your code, I don't know what you
    mean by the question or why you are bringing up something completely
    extraneous.
     
    Barry Schwarz, May 10, 2014
    #29
  10. A quibble: The C standard defines the term "compatible types",
    and the definition is much more strict than that. The definition
    is in N1570 6.2.7p1, with references to several other sections.
    To summarize:

    - A type is compatible with itself (this includes typedefs, of course).
    - An enum type is compatible with some integer type.
    - Two pointer types are compatible if they're identically qualified
    pointers to compatible types.
    - Two array types are compatible if they have compatible element types
    and have identical constant size, or if one of the types doesn't have
    a constant size (the latter case can cause undefined behavior if the
    sizes don't match).
    - Two function types are compatible if they have compatible return and
    parameter types, plus some other rules if one type has an old-style
    non-prototype declaration.

    int and long are definitely not compatible types. Incompatible types
    often have implicit conversions, but pointers to incompatible types do
    not (aside from the special case of void*).

    There doesn't seem to be a term in the standard for types that have an
    implicit conversion. Perhaps "assignment-compatible" would be
    reasonable.

    [...]
     
    Keith Thompson, May 10, 2014
    #30
  11. Bill Cunningham

    James Kuyper Guest

    On 05/10/2014 05:16 PM, Barry Schwarz wrote:
    ....
    Compatible scalar types can be implicitly converted to each other, but
    most implicit conversions apply to types that are not compatible with
    each other. Also, aggregate types can be compatible, but cannot be
    implicitly converted.

    The standard says that two types are compatible only in certain specific
    cases:

    (6.2.7p1):
    "Two types have compatible type if their types are the same.
    Additional rules for determining whether two types are compatible are
    described in 6.7.2 for type specifiers, in 6.7.3 for type qualifiers,
    and in 6.7.6 for declarators.55) Moreover two structure, union, or
    enumerated types declared in separate translation units are compatible
    if their tags and members satisfy the following requirements: If one is
    declared with a tag, the other shall be declared with the same tag. If
    both are completed anywhere within their respective translation units,
    then the following additional requirements apply: there shall be a
    one-to-one correspondence between their members such that each pair of
    corresponding members are declared with compatible types; if one member
    of the pair is declared with an alignment specifier, the other is
    declared with an equivalent alignment specifier; and if one member of
    the pair is declared with a name, the other is declared with the same
    name. For two structures, corresponding members shall be declared in the
    same order. For two structures or unions, corresponding bit-fields shall
    have the same widths. For two enumerations, corresponding members shall
    have the same values."

    Note that "two structure, union, or enumerated types declared in" the
    same translation unit are NOT compatible, not even if they meet all of
    those other requirements.

    Here are the "additional rules" referred to by that clause, in their
    entirety:

    6.7.2.2p4:
    "Each enumerated type shall be compatible with char, a signed integer
    type, or an unsigned integer type. The choice of type is
    implementation-defined, ..."

    6.7.3p10:
    "For two qualified types to be compatible, both shall have the
    identically qualified version of a compatible type ..."

    6.7.6.1p2:
    "For two pointer types to be compatible, both shall be identically
    qualified and both shall be pointers to compatible types."

    6.7.6.2p10: "For two array types to be compatible, both shall have
    compatible element types, and if both size specifiers are present, and
    are integer constant expressions, then both size specifiers shall have
    the same constant value."

    The fact that types with differing qualifiers (and pointers to those
    types) are NOT compatible is the key thing that renders invalid a lot of
    code that does things with qualified types that should NOT be done. For
    instance, declaring a variable with 'const' in one translation unit, and
    without it in another.

    The standard never defines directly what "compatible type" means. It
    only defines a single general case (same type) and a small number of
    special cases. It then goes on, in a variety of places, to require that
    under certain circumstances, it is a constraint violation or undefined
    behavior for two types to be incompatible.

    From what the standard does say, you can derive a few things that the
    standard does not say, at least not directly: compatible types are
    required to be implemented in essentially the same way, even if they're
    not the same type. At a minimum, they have to have the same
    representation, alignment requirement, and must be treated equivalently
    as function arguments or function return values.
     
    James Kuyper, May 11, 2014
    #31
  12. I will look. I can't guarantee understanding; but I will look and to my
    knowledge n1256 is the newest or maybe a n1257 exists. I can't remember
    which.

    Bill
     
    Bill Cunningham, May 11, 2014
    #32


  13. Ok so then is at least part of it size which would make the compiler
    warn of differing types? I understand I am dealing with an array of ints.
    The point is of type int, I guess just one int. malloc() could've been used
    here...

    malloc(5*sizeof(int)); // But that's usually for dynamic allocation. I did
    want the more "static" type of memory storage of an array. a can be
    considered a pointer in a sense too. So to assign a pointer to a pointer as
    p=a makes sense that way. More so than p=&a.


    Bill
     
    Bill Cunningham, May 11, 2014
    #33
  14. What you're probably thinking is that, for many C programs, data is
    incorporated into the program in arrays at compile time. For example the
    Baby X resource compiler does that. However whilst the size of an
    Baby X resource-compiler generated array is known at compile time,
    it's not generally known at program write time.

    Most algorithms which are defined for an array of N items are defined for
    all values of N, or for all values except a few degenerate cases like N = 0,
    or N = 1. There are exceptions, for example the cross-product. The dot product
    is defined for all N, however. A chess-playing function probably can't
    meanigfully operate on a board that isn't 8x8. However a snakes and ladders
    function probably shouldn't be hard-coded to boards 10x10.
     
    Malcolm McLean, May 11, 2014
    #34
  15. Bill Cunningham

    BartC Guest

    He has a point. C's implementation of arrays is somewhat lightweight.

    For example, it doesn't really have proper array indexing: A is almost
    universal in selecting element i of array A, but in C it is syntactic sugar
    for *(A+i); A here is really a pointer to a type which matches the element
    type of what would be the array.

    Other languages way well do exactly the same behind the scenes, but C does
    it openly (but in doing so, conflates arrays and pointers in a way that
    affects the integrity of the type system: see the 'Using char[] as function
    argument ... ' thread).

    And a C array doesn't officially have a length that you can interrogate,
    even though you used that same length to declare it! You have to calculate
    it indirectly by some arithmetic involving the byte-size of the whole array
    object, and the byte-size of one of its elements, as you demonstrated in
    another post.
     
    BartC, May 11, 2014
    #35
  16. Bill Cunningham

    BartC Guest

    I think he's right. Fixed length arrays have been only a small part of any
    sizeable program I've written.

    They might be used for small buffers, eg. char[100] to hold the result of
    some decimal expansion of a number for example.

    Or to construct data types where the size is an integral part: double[4][4]
    for a matrix for example; I wouldn't really consider that as an array type,
    but as a matrix type.

    Proper arrays tend to be large and/or dynamic, and here it is unusual to use
    a fixed size for them. Certainly when you pass an T[] array - fixed size or
    otherwise - to a function taking a T* parameter, the fixed length aspect is
    lost.
     
    BartC, May 11, 2014
    #36
  17. Bill Cunningham

    Ike Naar Guest

    Everyone from a programming background would also understand that you
    have had a problem operating your shift key ;-)
     
    Ike Naar, May 11, 2014
    #37
  18. Bill Cunningham

    James Kuyper Guest

    The overwhelming majority of the arrays in the code I work on have a
    fixed size, including all of the largest ones. For instance, in programs
    designed for processing MODIS data, the largest arrays tend to contain
    one dimension whose length is the number of detectors in a given band
    (10, 20, or 40 detectors, depending upon the band), and another whose
    length is the number of frames of of data collected during a single
    mirror scan (1354, 2708, or 5416 columns, with the same band
    dependence). All of those numbers were fixed when the MODIS instrument
    was first designed and built, and cannot be changed except by designing
    and building a new instrument. It is possible for the instrument to
    collect less than the maximum number of frames of data during a given
    scan, but that doesn't happen often enough to justify making that
    dimension variable. Even if the code gets ported to a new, similar
    instrument with different characteristics (which has, in fact,
    happened), that would just be a matter of changing some #defines, it is
    not a change that could ever occur at run time.

    I'm not saying that this is typical. I'm pointing out that there's a
    wide ranged of variation. Any general claim that "fixed size arrays
    aren't all that useful" is doomed to fail in specific cases, because
    it's built upon experience with one particular kind of computer programming.
     
    James Kuyper, May 11, 2014
    #38
  19. [snip]

    n1570 which I looked up is the C11 standard. I do not know a thing about
    that and my gcc doesn't seem to have any new possible C11 headers that I
    see. I must conclude that gcc isn't C11 compliant. I am just staring to use
    /some/ of C99.

    Bill
     
    Bill Cunningham, May 11, 2014
    #39
  20. Bill Cunningham

    Ian Collins Guest

    You appear to live in the land of the abstract. For those of us who
    live in the real world, fixed length arrays are a normal part of our
    programming life.
     
    Ian Collins, May 11, 2014
    #40
    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.