home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #27 / NN_1992_27.iso / spool / comp / lang / c / 17041 < prev    next >
Encoding:
Internet Message Format  |  1992-11-23  |  6.1 KB

  1. Path: sparky!uunet!crdgw1!rdsunx.crd.ge.com!bart!volpe
  2. From: volpe@bart.NoSubdomain.NoDomain (Christopher R Volpe)
  3. Newsgroups: comp.lang.c
  4. Subject: Re: Is this ANSI?
  5. Message-ID: <1992Nov23.175310.2216@crd.ge.com>
  6. Date: 23 Nov 92 17:53:10 GMT
  7. References: <9eRguB1w165w@quest.UUCP> <24238@alice.att.com> <1992Nov21.125038.26244@sq.sq.com> <24270@alice.att.com>
  8. Sender: volpe@bart (Christopher R Volpe)
  9. Reply-To: volpe@ausable.crd.ge.com
  10. Organization: GE Corporate Research & Development
  11. Lines: 172
  12. Nntp-Posting-Host: bart.crd.ge.com
  13.  
  14. In article <24270@alice.att.com>, ark@alice.att.com (Andrew Koenig) writes:
  15. |> In article <1992Nov21.125038.26244@sq.sq.com> msb@sq.sq.com (Mark Brader) writes:
  16. |> 
  17. |> > Andrew, I'm afraid that *you* are definitely wrong, period.
  18.  
  19. I agree with Mark.
  20.  
  21. |> 
  22. |> After thinking it over carefully, I'm not convinced.
  23. |> 
  24. |> > The key word here is "allocate", meaning that the intention is to
  25. |> > do something like
  26. |> 
  27. |> >     struct FM *p = malloc (sizeof (struct FM) + n);
  28. |> 
  29. |> Agreed.
  30.  
  31. [stuff deleted]
  32.  
  33. |> 
  34. |> Unfortunately, I wasn't in on that discussion.  But to convince me
  35. |> that it's legal, you'd have to find language in the standard that allows
  36. |> it.  I looked around a little bit, and here is what I found, in the description
  37. |> of pointer+integer:
  38. |> 
  39. |>     Unless both the pointer operand and the result point to
  40. |>     elements of the same array object, or the pointer
  41. |>     operand points one past the last element of an array
  42. |>     object and the result points to an element of the same
  43. |>     array object, the behavior is undefined if the result
  44. |>     is used as an operand of the unary * operator.
  45. |> 
  46. |> Now, let's take a look at the example again:
  47. |> 
  48. |>     struct FM {
  49. |>         int size;
  50. |>         char data[1];
  51. |>     };
  52. |> 
  53. |>     main()
  54. |>     {
  55. |>         struct FM *p = (struct FM *) malloc(sizeof(struct FM) + 100);
  56. |>         p->data[5] = '?';
  57. |>     }
  58. |> 
  59. |> At issue is the assignment to p->data[5].
  60. |> 
  61. |> As I see it, the question is just what p->data is.  If I look at the
  62.  
  63. p->data, as operand to the "[]" operator, decays into a pointer-to-char.
  64. It points somewhere within the block returned by malloc().
  65.  
  66. |> definition of p, I see that p->data is an array of char with one element.
  67.  
  68. After it decays, it no longer has array type.
  69.  
  70. |> The way I've used it is, of course, equivalent to *(p->data+5).
  71. |> 
  72. |> That means p->data is converted to a pointer to its initial element,
  73. |> namely a pointer to the first (and only) element of a one-element array.
  74. |> [Remember this assertion].  So, we take that pointer, add 5 to it,
  75. |> and apply unary * to the result.  Well, the pointer operand of +
  76. |> points to an element of the array object, but the result does not;
  77. |> there is only one element and the result doesn't point there.
  78. |> The result of using unary * is therefore undefined.
  79.  
  80. Both the operand and result point within the array-of-char returned by
  81. malloc.
  82.  
  83. |> 
  84. |> Now, look back at the assertion I asked you to remember.  I expect
  85. |> that Mark Brader is going to say `But p->data isn't an array of
  86. |> one element, it's an array of 101 elements.  After all, when you
  87. |> said malloc(sizeof(struct FM + 100), you allocated enough memory
  88. |> for 101 elements!'
  89. |> 
  90. |> Here are two reasons I disagree:
  91. |> 
  92. |>     1. Suppose I said
  93. |> 
  94. |>         struct FM *q = (struct FM *) malloc(sizeof(struct FM) + 100);
  95. |> 
  96. |>     and later said
  97. |> 
  98. |>         *p = *q;
  99. |> 
  100. |>     Is the compiler obligated to realize that p and q actually point
  101. |>     to objects of type other than struct FM?  That is, is it obligated
  102. |>     to copy all the `extra' elements in the data array?
  103.  
  104. Of course not. This is a bogus argument. Consider this:
  105.       int i[100];
  106.       int *p, *q=i;
  107.       p = malloc(100 * sizeof(int));
  108.  
  109. Now, if I do:
  110.   
  111.       *p = *q;
  112.  
  113. Is the compiler obligated to realize that p and q, which are declared as
  114. "pointer to int", actually point to something other than single ints? 
  115. Should it copy the entire array? Of course not. Does this mean that p[5]
  116. is an illegal reference?? Of course not. Otherwise, to allocate dynamic
  117. arrays of ints, one would have to do:
  118.  
  119.       typedef int array[100];
  120.       array *p;
  121.       p = (array *) malloc(sizeof(array));
  122.       /* blah blah blah */
  123.       (*p)[5] = whatever;
  124.  
  125.  
  126. |> 
  127. |>     2. If you declare p by saying
  128. |> 
  129. |>         struct FM *p;
  130. |> 
  131. |>     then I don't think there is any place in the standard that says
  132. |>     other than that *p is an lvalue of type FM.  Once you acknowledge
  133. |>     that *p is of type FM, I don't see how you can get away from the
  134.  
  135. Yes, *p is of type FM, just as in my example, *p was of type int.
  136. It's still not relevant. 
  137.  
  138. |>     p->data being anything other than a one-element array.  What I found
  139. |>     in the standard that talks about this is:
  140. |> 
  141. |> 
  142. |>         The pointer returned [by malloc or realloc] if the
  143. |>         allocation succeeds is suitably aligned so that it
  144. |>         may be assigned to a pointer to any type of object
  145. |>         and then used to access such an object or an array
  146. |>         of such objects in the space allocated (until the
  147. |>         space is explicitly freed or reallocated).
  148. |>     
  149. |>     It doesn't say that it may be assigned to a pointer to some
  150. |>     type of object and then used to access an object of some other
  151. |>     type.  That is, it says that the result of malloc may be
  152. |>     assigned to a struct FM * and then used to access an object
  153. |>     of type struct FM.  It says nothing about struct FM representing
  154. |>     a family of related types.
  155.  
  156.  
  157. There's no family of related types here. The type of interest is "char *",
  158. which is what p->data decays into.
  159.  
  160. |> 
  161. |> Another way to look at it is this.  Suppose I have a compiler that rejects:
  162. |> 
  163. |>     void f(struct FM *p)
  164. |>     {
  165. |>         p->data[5] = '?';
  166. |>     }
  167. |> 
  168. |> on the basis that p->data is a one-element array and you can't refer to
  169. |> the fifth element of a one-element array.  What part of the standard can
  170. |> you cite to convince me that my compiler isn't allowed to diagnose this?
  171.  
  172. It can diagnose it at runtime if it can determine that p->data and
  173. p->data+5 don't point within the same object. If it tries to do this at
  174. compile-time, file a bug report.
  175.  
  176. |> -- especially after the description of pointer arithmetic above?
  177. |> -- 
  178. |>                 --Andrew Koenig
  179. |>                   ark@europa.att.com
  180.  
  181. -- 
  182. ==================
  183. Chris Volpe
  184. G.E. Corporate R&D
  185. volpecr@crd.ge.com
  186.