Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #150646 > unrolled thread

allocating two objects in one malloc

Started byThiago Adams <thiago.adams@gmail.com>
First post2020-03-18 10:14 -0700
Last post2020-03-18 15:08 -0400
Articles 19 on this page of 39 — 12 participants

Back to article view | Back to comp.lang.c


Contents

  allocating two objects in one malloc Thiago Adams <thiago.adams@gmail.com> - 2020-03-18 10:14 -0700
    Re: allocating two objects in one malloc Bonita Montero <Bonita.Montero@gmail.com> - 2020-03-18 18:17 +0100
      Re: allocating two objects in one malloc Thiago Adams <thiago.adams@gmail.com> - 2020-03-18 10:55 -0700
        Re: allocating two objects in one malloc Thiago Adams <thiago.adams@gmail.com> - 2020-03-18 11:01 -0700
        Re: allocating two objects in one malloc felix@palmen-it.de (Felix Palmen) - 2020-03-18 19:14 +0100
          Re: allocating two objects in one malloc Thiago Adams <thiago.adams@gmail.com> - 2020-03-18 11:35 -0700
            Re: allocating two objects in one malloc felix@palmen-it.de (Felix Palmen) - 2020-03-18 19:44 +0100
              Re: allocating two objects in one malloc Thiago Adams <thiago.adams@gmail.com> - 2020-03-18 12:07 -0700
                Re: allocating two objects in one malloc Bart <bc@freeuk.com> - 2020-03-18 20:39 +0000
                  Re: allocating two objects in one malloc Thiago Adams <thiago.adams@gmail.com> - 2020-03-18 13:52 -0700
                Re: allocating two objects in one malloc felix@palmen-it.de (Felix Palmen) - 2020-03-18 23:11 +0100
                  Re: allocating two objects in one malloc Thiago Adams <thiago.adams@gmail.com> - 2020-03-18 16:48 -0700
                    Re: allocating two objects in one malloc Bart <bc@freeuk.com> - 2020-03-19 01:16 +0000
                      Re: allocating two objects in one malloc Thiago Adams <thiago.adams@gmail.com> - 2020-03-24 06:11 -0700
                        Re: allocating two objects in one malloc Ben Bacarisse <ben.usenet@bsb.me.uk> - 2020-03-24 14:49 +0000
                          Re: allocating two objects in one malloc Thiago Adams <thiago.adams@gmail.com> - 2020-03-24 08:46 -0700
                        Re: allocating two objects in one malloc James Kuyper <jameskuyper@alumni.caltech.edu> - 2020-03-24 07:50 -0700
                          Re: allocating two objects in one malloc Thiago Adams <thiago.adams@gmail.com> - 2020-03-24 08:48 -0700
                    Re: allocating two objects in one malloc chad <cdalten@gmail.com> - 2020-03-19 05:15 -0700
                    Re: allocating two objects in one malloc James Kuyper <jameskuyper@alumni.caltech.edu> - 2020-03-24 08:11 -0700
                      Re: allocating two objects in one malloc Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2020-03-24 11:35 -0400
                        Re: allocating two objects in one malloc Richard Damon <Richard@Damon-Family.org> - 2020-03-24 13:50 -0400
                          Re: allocating two objects in one malloc Ben Bacarisse <ben.usenet@bsb.me.uk> - 2020-03-24 20:58 +0000
                        Re: allocating two objects in one malloc Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2020-03-24 13:10 -0700
                      Re: allocating two objects in one malloc Thiago Adams <thiago.adams@gmail.com> - 2020-03-24 08:52 -0700
                        Re: allocating two objects in one malloc Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2020-03-24 13:05 -0700
            Re: allocating two objects in one malloc Bonita Montero <Bonita.Montero@gmail.com> - 2020-03-18 19:53 +0100
            Re: allocating two objects in one malloc Bart <bc@freeuk.com> - 2020-03-18 20:29 +0000
            Re: allocating two objects in one malloc jadill33@gmail.com - 2020-03-18 13:44 -0700
            Re: allocating two objects in one malloc Ben Bacarisse <ben.usenet@bsb.me.uk> - 2020-03-18 21:00 +0000
    Re: allocating two objects in one malloc Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2020-03-18 10:18 -0700
    Re: allocating two objects in one malloc felix@palmen-it.de (Felix Palmen) - 2020-03-18 18:43 +0100
      Re: allocating two objects in one malloc Bonita Montero <Bonita.Montero@gmail.com> - 2020-03-18 18:55 +0100
        Re: allocating two objects in one malloc Thiago Adams <thiago.adams@gmail.com> - 2020-03-18 10:56 -0700
          Re: allocating two objects in one malloc Bonita Montero <Bonita.Montero@gmail.com> - 2020-03-18 19:06 +0100
        Re: allocating two objects in one malloc felix@palmen-it.de (Felix Palmen) - 2020-03-18 19:01 +0100
      Re: allocating two objects in one malloc James Kuyper <jameskuyper@alumni.caltech.edu> - 2020-03-18 14:21 -0400
        Re: allocating two objects in one malloc felix@palmen-it.de (Felix Palmen) - 2020-03-18 19:30 +0100
          Re: allocating two objects in one malloc James Kuyper <jameskuyper@alumni.caltech.edu> - 2020-03-18 15:08 -0400

Page 2 of 2 — ← Prev page 1 [2]


#150803

FromLew Pitcher <lew.pitcher@digitalfreehold.ca>
Date2020-03-24 11:35 -0400
Message-ID<r5d9bt$4ak$1@dont-email.me>
In reply to#150802
On March 24, 2020 11:11, James Kuyper wrote:

> On Wednesday, March 18, 2020 at 7:48:47 PM UTC-4, Thiago Adams wrote:
> ...
>> Something I  have considered to suggest for the C language
>> is make the operator [] available for empty arrays at the end.
>> 
>> 
>> struct array
>> {
>>   int size;
>>   int capacity;
>>   char data[];
>> };
> 
> You're 21 years late - flexible array members were added in C99.
[snip]

To me, this seems to be a re-implementation of a pattern seen in 40-year-old 
programs written to the K&R standard. Specifically, in programs with a 
structure like
  struct item
  {
    int something;	/* 2 chars long (PDP-11 C) */
    char data[1];	/* 1 char long  (PDP-11 C) */
  } *X;

K&R C allowed (but did not encourage)

  X = alloc(9);			/* 3 for the given struct, 6 as overflow */
  strcpy(X->data,"sixSIX");	/* treats data[] as having 7 elements */ 

-- 
Lew Pitcher
"In Skills, We Trust"

[toc] | [prev] | [next] | [standalone]


#150808

FromRichard Damon <Richard@Damon-Family.org>
Date2020-03-24 13:50 -0400
Message-ID<fLreG.468338$ss1.301745@fx42.iad>
In reply to#150803
On 3/24/20 11:35 AM, Lew Pitcher wrote:
> On March 24, 2020 11:11, James Kuyper wrote:
> 
>> On Wednesday, March 18, 2020 at 7:48:47 PM UTC-4, Thiago Adams wrote:
>> ...
>>> Something I  have considered to suggest for the C language
>>> is make the operator [] available for empty arrays at the end.
>>>
>>>
>>> struct array
>>> {
>>>   int size;
>>>   int capacity;
>>>   char data[];
>>> };
>>
>> You're 21 years late - flexible array members were added in C99.
> [snip]
> 
> To me, this seems to be a re-implementation of a pattern seen in 40-year-old 
> programs written to the K&R standard. Specifically, in programs with a 
> structure like
>   struct item
>   {
>     int something;	/* 2 chars long (PDP-11 C) */
>     char data[1];	/* 1 char long  (PDP-11 C) */
>   } *X;
> 
> K&R C allowed (but did not encourage)
> 
>   X = alloc(9);			/* 3 for the given struct, 6 as overflow */
>   strcpy(X->data,"sixSIX");	/* treats data[] as having 7 elements */ 
> 

There were two ways of implementing this prior to C99.

One was as you showed, declaring an array of length 1, and then
accessing pass it. Technically, this invoked undefined behavior, which
the implementation was allowed to do any number of behaviors, like trap,
give an error or even optimize based on the fact that it KNEW the array
only had 1 member. It also caused the object to contain 1 copy of the
object, so you add to allocate sizeof(item) + (n-1)*sizeof(char).

I don't think K&R explicitly allowing this, it is just that compilers of
that era didn't do optimizations that would cause it problems.

A second method was like that, but used the other illegal dimension of
0., this made it clear that you were wanting to invoke this feature, so
the compiler, if it accepted the code, was less apt to optimize against it.

As a 'compromise', the committee created a new syntax, the [], which was
clearer than the 0 (which might have occurred by accident if the size
was a macro or computed, while still allowing the compiler to optimize
most array accesses to known sized arrays.

[toc] | [prev] | [next] | [standalone]


#150812

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2020-03-24 20:58 +0000
Message-ID<87h7yd1nco.fsf@bsb.me.uk>
In reply to#150808
Richard Damon <Richard@Damon-Family.org> writes:

> As a 'compromise', the committee created a new syntax, the [], which was
> clearer than the 0 (which might have occurred by accident if the size
> was a macro or computed, while still allowing the compiler to optimize
> most array accesses to known sized arrays.

(not really replying... just finding a post to attach this remark to.)

The [] syntax has another advantage: a compiler can tell you when you
use it in dangerous contexts.  An array of structs with a flexible array
member is not meaningful, as is using one as a member of another struct.
An array of size 1 might, at a pinch, be just that, and complaining
about it being used in those contexts could be annoying.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#150811

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2020-03-24 13:10 -0700
Message-ID<87ftdxpl9g.fsf@nosuchdomain.example.com>
In reply to#150803
Lew Pitcher <lew.pitcher@digitalfreehold.ca> writes:
> On March 24, 2020 11:11, James Kuyper wrote:
>> On Wednesday, March 18, 2020 at 7:48:47 PM UTC-4, Thiago Adams wrote:
>> ...
>>> Something I  have considered to suggest for the C language
>>> is make the operator [] available for empty arrays at the end.
>>> 
>>> 
>>> struct array
>>> {
>>>   int size;
>>>   int capacity;
>>>   char data[];
>>> };
>> 
>> You're 21 years late - flexible array members were added in C99.
> [snip]
>
> To me, this seems to be a re-implementation of a pattern seen in 40-year-old 
> programs written to the K&R standard.

Yes, that's exactly what it is.

The old pattern is called the "struct hack".  It worked as expected with
more or all compilers, but strictly speaking it had (and still has)
undefined behavior.  Quoting the C99 Rationale:

    The Committee felt that, although there was no way to
    implement the “struct hack” in C89, it was nonetheless a
    useful facility. Therefore the new feature of “flexible array
    members” was introduced. Apart from the empty brackets, and the
    removal of the “-1” in the malloc call, this is used in the
    same way as the struct hack, but is now explicitly valid code.

See also question 2.6 of the comp.lang.c FAQ <http://www.c-faq.com/>.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#150806

FromThiago Adams <thiago.adams@gmail.com>
Date2020-03-24 08:52 -0700
Message-ID<bd5529e8-ff39-412a-8b73-17d8456a2052@googlegroups.com>
In reply to#150802
On Tuesday, March 24, 2020 at 12:12:10 PM UTC-3, James Kuyper wrote:
> On Wednesday, March 18, 2020 at 7:48:47 PM UTC-4, Thiago Adams wrote:
> ...
> > Something I  have considered to suggest for the C language
> > is make the operator [] available for empty arrays at the end.
> > 
> > 
> > struct array
> > {
> >   int size;
> >   int capacity;
> >   char data[];
> > };
> 
> You're 21 years late - flexible array members were added in C99.

My suggestion is not add flexible arrays.
It is make the operator [ ] works as synonymous 

sample (Array has the flexible array member called data)

struct Array a;
a[0] = 1;
 
same as or synonymous of :

a.data[0] = 1;

my suggestion is make this a[0] syntax synonymous of
a.data[0] where data or other name is the flexible array
member.

This is useful in case we want to put some information
together with arrays and still use array notation.

[toc] | [prev] | [next] | [standalone]


#150810

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2020-03-24 13:05 -0700
Message-ID<87k139plh4.fsf@nosuchdomain.example.com>
In reply to#150806
Thiago Adams <thiago.adams@gmail.com> writes:
> On Tuesday, March 24, 2020 at 12:12:10 PM UTC-3, James Kuyper wrote:
>> On Wednesday, March 18, 2020 at 7:48:47 PM UTC-4, Thiago Adams wrote:
>> ...
>> > Something I  have considered to suggest for the C language
>> > is make the operator [] available for empty arrays at the end.
>> > 
>> > 
>> > struct array
>> > {
>> >   int size;
>> >   int capacity;
>> >   char data[];
>> > };
>> 
>> You're 21 years late - flexible array members were added in C99.
>
> My suggestion is not add flexible arrays.
> It is make the operator [ ] works as synonymous 
>
> sample (Array has the flexible array member called data)
>
> struct Array a;
> a[0] = 1;
>  
> same as or synonymous of :
>
> a.data[0] = 1;
>
> my suggestion is make this a[0] syntax synonymous of
> a.data[0] where data or other name is the flexible array
> member.
>
> This is useful in case we want to put some information
> together with arrays and still use array notation.

That sounds like enabling operator overloading, but only for this one
specific case.  IMHO it's not sufficiently useful.

You can, if you like, do something like this:

    struct Array a;
    #define a_a a.data
    a_a[0] = 1;

(Please pretend that I picked more meaningful names.)

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#150662

FromBonita Montero <Bonita.Montero@gmail.com>
Date2020-03-18 19:53 +0100
Message-ID<r4tqmf$185$1@news.albasani.net>
In reply to#150660
> #define ArrayPush(A, V)\
> do {\
>      if ((A)->size + 1 > (A)->capacity)\
>      {\
>          int n = (A)->capacity * 2;\
>          if (n == 0)\
>          {\
>              n = 1;\
>          }\
>          void* pnew = (A)->data;\
>          pnew = realloc(pnew, n * sizeof((A)->data[0]));\
>          if (pnew)\
>          {\
>              (A)->data = pnew;\
>              (A)->capacity = n;\
>              (A)->data[(A)->size] = (V); \
>              (A)->size++;\
>          }\
>      } else \
>      {\
>        (A)->data[(A)->size] = (V);\
>        (A)->size++;\
>      }\
> }while(0)

This is an example of why C sucks so much and C++ is so superior.

[toc] | [prev] | [next] | [standalone]


#150669

FromBart <bc@freeuk.com>
Date2020-03-18 20:29 +0000
Message-ID<0xvcG.345279$g%7.190337@fx07.am4>
In reply to#150660
On 18/03/2020 18:35, Thiago Adams wrote:
> On Wednesday, March 18, 2020 at 3:16:09 PM UTC-3, Felix Palmen wrote:
>> * Thiago Adams
>>> I want to use it in a macro for any type.
>>
>> BAD idea, IMHO. As soon as your member type isn't `char`, you'll have
>> problems with your initial idea (alignment, but also aliasing).
>>
>> If you need an abstract container, either use a good existing
>> implementation (e.g. glib has these), or do it yourself.
>> A void pointer member might be good enough for your usecase.
>> You should definitely have two allocations, because you will have to
>> reallocate the "member array" when the size changes, and you probably
>> don't want to reallocate your metadata (size and capacity) as well.
>>
>> If the list of types needed is known in advance, you might also want to
>> play around with generic selection.
>>
>>> But maybe union.. (I would use this only if the previous
>>> approach is not sufficient)
>>>
>>> struct Array
>>> {
>>>    int size;
>>>    int capacity;
>>>    union {
>>>     int i;
>>>     double d; ... } data[];
>>> };
>>
>> This would potentially waste a lot of memory.
> 
> I am doing an exercise and thinking how a reziable
> array type would be implemented under the hood in C.
> 
> I would like a type declared as:
> 
> int a[auto];
> assert(array_size(a) == 0);
> push(a, 1);
> assert(array_size(a) == 1);
> 
> How this array would be implemented by the compiler?
> What is the best option?
> 
> I have two approaches:
> 
> 1 - (similar of C++ vector)
>      struct { int size; int capacity; T* data; };
>   
> 2 - Pointer, pointing to the object that has size and capacity
>      allocated together.

I'd got for #1 I think.

This allows you also to have views and slices into existing arrays 
(allowing substrings for example).

Or it can be set up to point into ordinary arrays (so you can pass 
either kind to the same function).

And it can be adapted for shared arrays by adding ref-counting (by 
adding a field).

Or adapted the other way by removing the capacity field, ending up with 
a simple slice.

[toc] | [prev] | [next] | [standalone]


#150672

Fromjadill33@gmail.com
Date2020-03-18 13:44 -0700
Message-ID<10f12ac1-1b50-4ae1-911b-a5a63cc441e0@googlegroups.com>
In reply to#150660
On Wednesday, March 18, 2020 at 2:35:38 PM UTC-4, Thiago Adams wrote:
> On Wednesday, March 18, 2020 at 3:16:09 PM UTC-3, Felix Palmen wrote:
> > * Thiago Adams 
> > > I want to use it in a macro for any type. 
> > 
> > BAD idea, IMHO. As soon as your member type isn't `char`, you'll have
> > problems with your initial idea (alignment, but also aliasing).
> > 
> > If you need an abstract container, either use a good existing
> > implementation (e.g. glib has these), or do it yourself.
> > A void pointer member might be good enough for your usecase.
> > You should definitely have two allocations, because you will have to
> > reallocate the "member array" when the size changes, and you probably
> > don't want to reallocate your metadata (size and capacity) as well.
> > 
> > If the list of types needed is known in advance, you might also want to
> > play around with generic selection.
> > 
> > > But maybe union.. (I would use this only if the previous
> > > approach is not sufficient)
> > > 
> > > struct Array
> > > {
> > >   int size;
> > >   int capacity;
> > >   union {
> > >    int i;
> > >    double d; ... } data[];
> > > };
> > 
> > This would potentially waste a lot of memory.
> 
> I am doing an exercise and thinking how a reziable 
> array type would be implemented under the hood in C.
> 
> I would like a type declared as:
> 
> int a[auto];
> assert(array_size(a) == 0);
> push(a, 1);
> assert(array_size(a) == 1);
> 
> How this array would be implemented by the compiler?
> What is the best option?
> 
> I have two approaches:
> 
> 1 - (similar of C++ vector) 
>     struct { int size; int capacity; T* data; };
>  
> 2 - Pointer, pointing to the object that has size and capacity 
>     allocated together.
> 
> 
> Macros for approach 1:
> 
> #define ArrayOf(T) { T* data; int size; int capacity; }
> 
> #define ArrayPush(A, V)\
> do {\
>     if ((A)->size + 1 > (A)->capacity)\
>     {\
>         int n = (A)->capacity * 2;\
>         if (n == 0)\
>         {\
>             n = 1;\
>         }\
>         void* pnew = (A)->data;\
>         pnew = realloc(pnew, n * sizeof((A)->data[0]));\
>         if (pnew)\
>         {\
>             (A)->data = pnew;\
>             (A)->capacity = n;\
>             (A)->data[(A)->size] = (V); \
>             (A)->size++;\
>         }\
>     } else \
>     {\
>       (A)->data[(A)->size] = (V);\
>       (A)->size++;\
>     }\
> }while(0)
> 
> int main()
> {
>     struct ArrayOf(int) a = { 0 };
>     for (int j = 0; j < 10; j++)
>     {
>         ArrayPush(&a, j);
>     }
> }
> 
> Macros for approach 2
> 
> #define array_size(a)  ((a) ? (((int*)((char*)(a) - sizeof(int) * 2))[0]) : 0)
> #define array_capacity(a)  ((a) ? (((int*)((char*)(a) - sizeof(int) * 2))[1]) : 0)
> #define array_free(a) if (a) free((((int*)((char*)(a) - sizeof(int) * 2))))
> 
> #define array_push(p, value) \
>   do {\
>     int* pints = p ? ((int*)((char*)(p) - sizeof(int) * 2)) : 0;\
>     int size = pints ? pints[0] : 0;\
>     int capacity = pints ? pints[1] : 0;\
>     if (size + 1 > capacity) {\
>       int n = capacity * 2;\
>       if (n == 0) {\
>          n = 1;\
>       }\
>       pints = (int*)realloc(pints, sizeof(int) * 2 + n * sizeof(p[0]));\
>       if (pints) {\
>          p = ((void*)((char*)(pints) + sizeof(int) * 2));\
>          pints[0] = size;\
>          pints[1] = n;\
>       }\
>     }\
>    p[size] = value;\
>    pints[0]++;\
>   } while (0)
> 
> 
> struct X
> {
>     int i;
> };
> 
> int main()
> {
>     struct X* pX = { 0 };
>     
>     array_push(pX, (struct X) {.i = 1});
>     array_push(pX, (struct X) {.i = 2});
>     
>     for (int i = 0; i < array_size(pX); i++)
>     {
>         printf("%d\n", pX[i].i);
>     }
>     array_free(pX);
> }

I have played around with this idea in the past.  This is what I came up with.

1. Use a struct defining a void* buffer, an element size, the array size and
capacity.

/*!
 * \struct c_array
 * \brief Define the structure for a dynamic resizable array.
 */
struct c_array
{
  /*! \brief The array's memory buffer. */
  void* buffer;

  /*! \brief The number of elements in the array. */
  size_t size;

  /*! \brief The allocated number of objects in the array's buffer. */
  size_t alloc_size;

  /*! \brief The size of each element in the array. */
  size_t element_size;
};

2. Use a type agnostic array interface defined as functions that take void*
and element size.

struct c_array* gc_array_alloc( size_t sz, size_t n );
void gc_array_push_back( struct c_array* array, void* object, size_t type_sz );
void* gc_array_front( struct c_array* array );

3. Use a macro array interface where you pass the type as a parameter, and
you can use sizeof to convert the type into the generic interface.

#define c_array_new( type, n ) (gc_array_alloc( sizeof (type), (n) ))
#define c_array_push_back( array, object, type )\
 (gc_array_push_back( (array), (object), sizeof (type) ))
#define c_array_front( array, type ) ( (type*)(gc_array_front( (array) )) )

I'd also take some time to explore other efforts, glib, sglib, ccl, etc.

Best regards,
John D.

[toc] | [prev] | [next] | [standalone]


#150674

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2020-03-18 21:00 +0000
Message-ID<87pnd9gyzk.fsf@bsb.me.uk>
In reply to#150660
Thiago Adams <thiago.adams@gmail.com> writes:

> I am doing an exercise and thinking how a reziable 
> array type would be implemented under the hood in C.
<cut>
> I have two approaches:
>
> 1 - (similar of C++ vector) 
>     struct { int size; int capacity; T* data; };

Can you not use a flexible array member:

  struct { int size, capacity; T data[]; };

?
  
> 2 - Pointer, pointing to the object that has size and capacity 
>     allocated together.

<cut>
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#150648

FromMalcolm McLean <malcolm.arthur.mclean@gmail.com>
Date2020-03-18 10:18 -0700
Message-ID<27d93c17-eb7a-4b9c-9df5-e0f9e3cf4459@googlegroups.com>
In reply to#150646
On Wednesday, 18 March 2020 17:14:57 UTC, Thiago Adams  wrote:
> I want to allocate an object array of some type using malloc and 
> allocate together two integers.(int or size_t)
> 
> My concern is alignment.
> 
> 
> Does this code is right?
> 
>     I will allocate 100 chars plus two ints.
> 
>     int n = 100;
>     int *p = (int*) malloc(sizeof(int) * 2 + sizeof(char) * n);
> 
>     I guess this part if fine because malloc already aligned
> 
>     p[0] = 0;
>     p[1] = n;
> 
> 
>     Now I want to use the char part going sizeof(int)*2 bytes ahead:
> 
>     char* pChars = (char*)((char*)p + sizeof(int) * 2);
>     strncpy(pChars, "test", 100-1);
> 
>     And here I want to go from chars back to int.
> 
>     int  *pInts =  (int*)((char*)pChars - sizeof(int) * 2);
>     pInts[0] = 0;
>     pInts[1] = n;
>
It works for chars because chars always have an alignment requirement of one. However it wouldn't necessarily work for other types as the second type.

[toc] | [prev] | [next] | [standalone]


#150650

Fromfelix@palmen-it.de (Felix Palmen)
Date2020-03-18 18:43 +0100
Message-ID<473akg-l3a2.ln1@mail.home.palmen-it.de>
In reply to#150646
* Thiago Adams <thiago.adams@gmail.com>:
> I want to allocate an object array of some type using malloc and 
> allocate together two integers.(int or size_t)

That's what structs are for.

>     int n = 100;
>     int *p = (int*) malloc(sizeof(int) * 2 + sizeof(char) * n);

Just: why? This is unreadable and error-prone. And using this construct
as you intend to is aliasing -- in this special case allowable, because
`char` may alias anything else, but still a code smell, if it's done
without a compelling reason. An allocated object gets its effective type
on the first write to it, so the instant you write an integer to p[0], p
is a pointer to int.

Furthermore, casting the result of malloc is a C++-ism.

A sane version for your allocation could look like this:

    struct fooarray
    {
      int num[2];
      char content[];
    };
    [...]

    int n = 100;
    struct fooarray *p = malloc(sizeof *p + n);

-- 
 Dipl.-Inform. Felix Palmen  <felix@palmen-it.de>   ,.//..........
 {web}  http://palmen-it.de  {jabber} [see email]   ,//palmen-it.de
 {pgp public key}     http://palmen-it.de/pub.txt   //   """""""""""
 {pgp fingerprint} A891 3D55 5F2E 3A74 3965 B997 3EF2 8B0A BC02 DA2A

[toc] | [prev] | [next] | [standalone]


#150651

FromBonita Montero <Bonita.Montero@gmail.com>
Date2020-03-18 18:55 +0100
Message-ID<r4tnae$80c$1@news.albasani.net>
In reply to#150650
>      struct fooarray
>      {
>        int num[2];
>        char content[];
>      };

AFAIK this empty arrays aren't part of the standard.

[toc] | [prev] | [next] | [standalone]


#150653

FromThiago Adams <thiago.adams@gmail.com>
Date2020-03-18 10:56 -0700
Message-ID<ae37e21a-6a91-43d5-b041-fff72a308cf3@googlegroups.com>
In reply to#150651
On Wednesday, March 18, 2020 at 2:55:35 PM UTC-3, Bonita Montero wrote:
> >      struct fooarray
> >      {
> >        int num[2];
> >        char content[];
> >      };
> 
> AFAIK this empty arrays aren't part of the standard.
Yes there are. C99

[toc] | [prev] | [next] | [standalone]


#150656

FromBonita Montero <Bonita.Montero@gmail.com>
Date2020-03-18 19:06 +0100
Message-ID<r4tnut$6ub$1@news.albasani.net>
In reply to#150653
>>>       struct fooarray
>>>       {
>>>         int num[2];
>>>         char content[];
>>>       };
>>

>> AFAIK this empty arrays aren't part of the standard.

> Yes there are. C99

Ok, didn't know this.
But I think that's a rather dirty feature - typical for C.

[toc] | [prev] | [next] | [standalone]


#150655

Fromfelix@palmen-it.de (Felix Palmen)
Date2020-03-18 19:01 +0100
Message-ID<684akg-ai21.ln1@mail.home.palmen-it.de>
In reply to#150651
* Bonita Montero <Bonita.Montero@gmail.com>:
>>      struct fooarray
>>      {
>>        int num[2];
>>        char content[];
>>      };
> 
> AFAIK this empty arrays aren't part of the standard.

If by standard, you mean C89, then you're right. The (not entirely
well-defined) workaround for those ages old compilers is

    struct fooarray
    {
      int num[2];
      char content[1];
    };

    [...]
    int n = 100
    struct fooarray *p = malloc(sizeof *p + n - 1);

It normally works in practice.

If your compiler isn't a dinosaur, a last struct member without a
declared size is called a "flexible array member" since C99.

-- 
 Dipl.-Inform. Felix Palmen  <felix@palmen-it.de>   ,.//..........
 {web}  http://palmen-it.de  {jabber} [see email]   ,//palmen-it.de
 {pgp public key}     http://palmen-it.de/pub.txt   //   """""""""""
 {pgp fingerprint} A891 3D55 5F2E 3A74 3965 B997 3EF2 8B0A BC02 DA2A

[toc] | [prev] | [next] | [standalone]


#150658

FromJames Kuyper <jameskuyper@alumni.caltech.edu>
Date2020-03-18 14:21 -0400
Message-ID<r4torg$evs$1@dont-email.me>
In reply to#150650
On 3/18/20 1:43 PM, Felix Palmen wrote:
> * Thiago Adams <thiago.adams@gmail.com>:
>> I want to allocate an object array of some type using malloc and 
>> allocate together two integers.(int or size_t)
> 
> That's what structs are for.
> 
>>     int n = 100;
>>     int *p = (int*) malloc(sizeof(int) * 2 + sizeof(char) * n);
> 
> Just: why? This is unreadable and error-prone. And using this construct
> as you intend to is aliasing -- in this special case allowable, because
> `char` may alias anything else, but still a code smell, if it's done
> without a compelling reason. An allocated object gets its effective type
> on the first write to it, so the instant you write an integer to p[0], p
> is a pointer to int.

'p' is always a pointer to int, whether or not it has ever been used in
an expression.
Something like that would be acceptable even if char wasn't one of the
two types in question. The expression p[0] does not access the entire
object allocated by that call to malloc(), it only accesses a single int
sub-object at the start of that block of memory. Therefore, it's only
that sub-object which acquires an effective type of 'int'. You can
therefore, if you take care to avoid overlap and ensure correct
alignment, give different effective types to different parts of a single
allocation without running afoul of the anti-aliasing rules.

A lot of software depends upon that. For instance, I once had to figure
out in detail how the IMSL library allocated multidimensional objects.
The header for such an object was a struct type containing a integer
rank for the array, a pointer to an array of integers of that length
containing the dimensions of that array, and a pointer to the actual
floating point data contained in the array. Those things were not
separately allocated. The IMSL library allocated a single block of
memory sufficiently large to hold the header, the dimensions array, and
the data. It placed the header at the start of the block, then
constructed the dimensions array immediately after it, and constructed
the data array immediately after that, filling in the header with
pointers to those items, then returned a pointer to the header. The
entire data structure would therefore be free()d by a single call to
free() using that pointer. I seem to recall that there were some
additional complications, but I no longer remember the details - the
part I did remember is sufficient to make my point.

In C99, the header could have contained the dimensions array as a
flexible array member, but that version of the IMSL library predated C99.

> Furthermore, casting the result of malloc is a C++-ism.

Agreed. The cast is unnecessary in C. If, by any chance, your code needs
to be compatible with C90 or a pre-standard compiler, the cast can even
hide an error in your code.

> A sane version for your allocation could look like this:
> 
>     struct fooarray
>     {
>       int num[2];
>       char content[];
>     };
>     [...]
> 
>     int n = 100;
>     struct fooarray *p = malloc(sizeof *p + n);

I certainly agree that this is a better approach. But the other way,
despite its faults, does have well-defined behavior.

[toc] | [prev] | [next] | [standalone]


#150659

Fromfelix@palmen-it.de (Felix Palmen)
Date2020-03-18 19:30 +0100
Message-ID<av5akg-i9f.ln1@mail.home.palmen-it.de>
In reply to#150658
* James Kuyper <jameskuyper@alumni.caltech.edu>:
> 'p' is always a pointer to int, whether or not it has ever been used in
> an expression.

That was a lapse I didn't deem important enough for posting a supersede,
but yes, I noticed that ;) Of course I meant the object pointed to by p.

> Something like that would be acceptable even if char wasn't one of the
> two types in question. The expression p[0] does not access the entire
> object allocated by that call to malloc(), it only accesses a single int
> sub-object at the start of that block of memory. Therefore, it's only
> that sub-object which acquires an effective type of 'int'. You can
> therefore, if you take care to avoid overlap and ensure correct
> alignment, give different effective types to different parts of a single
> allocation without running afoul of the anti-aliasing rules.

Well, that's an interpretation of the standard. Reading it, I found
nothing enforcing this interpretation. If you can prove it by citing the
standard, this would be pretty interesting.

In any case, I agree this won't ever be a /practical/ problem.

-- 
 Dipl.-Inform. Felix Palmen  <felix@palmen-it.de>   ,.//..........
 {web}  http://palmen-it.de  {jabber} [see email]   ,//palmen-it.de
 {pgp public key}     http://palmen-it.de/pub.txt   //   """""""""""
 {pgp fingerprint} A891 3D55 5F2E 3A74 3965 B997 3EF2 8B0A BC02 DA2A

[toc] | [prev] | [next] | [standalone]


#150664

FromJames Kuyper <jameskuyper@alumni.caltech.edu>
Date2020-03-18 15:08 -0400
Message-ID<r4trjl$24g$1@dont-email.me>
In reply to#150659
On 3/18/20 2:30 PM, Felix Palmen wrote:
> * James Kuyper <jameskuyper@alumni.caltech.edu>:
...
>> Something like that would be acceptable even if char wasn't one of the
>> two types in question. The expression p[0] does not access the entire
>> object allocated by that call to malloc(), it only accesses a single int
>> sub-object at the start of that block of memory. Therefore, it's only
>> that sub-object which acquires an effective type of 'int'. You can
>> therefore, if you take care to avoid overlap and ensure correct
>> alignment, give different effective types to different parts of a single
>> allocation without running afoul of the anti-aliasing rules.
> 
> Well, that's an interpretation of the standard. Reading it, I found
> nothing enforcing this interpretation. If you can prove it by citing the
> standard, this would be pretty interesting.

"If a value is stored into an object having no declared type through an
lvalue having a type that is not a character type, then the type of the
lvalue becomes the effective type of the object for that access and for
subsequent accesses that do not modify the stored value." (6.5p7).

Note that it is ONLY the object that's been stored into that acquires
that effective type. This doesn't apply to any other object just because
the object stored to happens to be a sub-object of the other object.

Also, keep in mind what the above clause would mean if it DID apply to
the entire allocated object, and not just the sub-object accessed by
p[0]. What is the type of that lvalue? It's "int". So if that clause did
apply to the entire allocated object, it would be saying that the
effective type of that entire allocated object would be "int". Not
"array of int", but simply "int". And that object is much too big to
have that type.

> In any case, I agree this won't ever be a /practical/ problem.

Actually, disagreement on this point between the implementor of an
implementation of C, and a developer who's using that implementation,
could result in the implementation optimizing the developer's code in
ways that the developer didn't consider legal, causing it to have
behavior the developer didn't expect it could have. So it can be a very
practical problem. It's important to know which interpretation is correct.

[toc] | [prev] | [standalone]


Page 2 of 2 — ← Prev page 1 [2]

Back to top | Article view | comp.lang.c


csiph-web