Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #110525 > unrolled thread
| Started by | "Patrick.Schluter" <Patrick.Schluter@free.fr> |
|---|---|
| First post | 2017-05-24 08:16 +0200 |
| Last post | 2017-06-04 18:24 +1000 |
| Articles | 4 — 2 participants |
Back to article view | Back to comp.lang.c
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: sizeof(x) / sizeof(x[0]) "Patrick.Schluter" <Patrick.Schluter@free.fr> - 2017-05-24 08:16 +0200
Re: sizeof(x) / sizeof(x[0]) "Peter \"Shaggy\" Haywood" <phaywood@alphalink.com.au> - 2017-05-27 17:44 +1000
Re: sizeof(x) / sizeof(x[0]) "Patrick.Schluter" <Patrick.Schluter@free.fr> - 2017-05-28 13:52 +0200
Re: sizeof(x) / sizeof(x[0]) "Peter \"Shaggy\" Haywood" <phaywood@alphalink.com.au> - 2017-06-04 18:24 +1000
| From | "Patrick.Schluter" <Patrick.Schluter@free.fr> |
|---|---|
| Date | 2017-05-24 08:16 +0200 |
| Subject | Re: sizeof(x) / sizeof(x[0]) |
| Message-ID | <59252557$0$15332$426a74cc@news.free.fr> |
Le 14.01.2017 à 13:16, Alla _ a écrit :
> Hello!
>
> Please, read my explanation before answering, to show
> my mistake.
> Honestly, for some time now I was sure I have no problems
> with the statement sizeof(x) / sizeof(x[0]), usually used as
> the macro to compute the size of an array of strings. I was
> positive that I know how it works, and didn't doubt.
> Somehow today when I used this macro again I've experienced
> a confusion - how does it work, and what have I completely
> forgotten? Although shameful, I have decided to come here again
> for help on this matter.
>
> For example:
> char *array[] = {"abc", "defg", "hijklmop", NULL};
> The pointer points to an array that has 4 strings.
> sizeof(x) here will be sizeof(array) thus indicating
> the size in bytes of the whole array of strings,
> because 'array' here is used as the address of the
> first sub-element, which is 'a' (array is the same as
> array[0][0]);
>
> so sizeof(array) will give the number of bytes occupied
> by the whole array of strings, i.e. number
> of characters x 1 (which is the size of a char);
>
> the denominator sizeof(x[0]) gives the size of the
> first element of the array, i.e. the size of the first
> string, which is here "abc", so it it is 3 (3 characters,
> each 1 byte); and all other strings have different
> number of characters in them, and hence different
> number of bytes;
>
> how then sizeof(x) / sizeof(x[0]) gives a correct number
> of strings in the array (it actually does, I have tested it
> on different strings)? Please, show me my mistake.
>
As other have explained, that macro falls apart when applied to a
pointer instead of an array. Something that can happen quite easily. The
thing to do in practice and if you use gcc is to use an extension to
make sure it is really an array and not a *. Here a macro inspired from
the one used in Linux kernel
#ifdef __GNUC__
#define NUM_ELEMS(arr) (sizeof(struct {int
:-!!(__builtin_types_compatible_p(typeof (arr), typeof
(&0[arr])));})+sizeof arr/sizeof 0[arr])
#else
/* A portable variant, but which doesn't check for array or pointer. */
#define NUM_ELEMS(arr) (sizeof arr/sizeof 0[arr])
#endif
2 remarks:
1 the 0[arr] is just a little trick so that one doesn't need the extra
parenthesis around the macro parameter.
2 sizeof arr also hasn't the parenthesis, this I did to enforce that the
MACRO is not invoked with a type but with a array name.
[toc] | [next] | [standalone]
| From | "Peter \"Shaggy\" Haywood" <phaywood@alphalink.com.au> |
|---|---|
| Date | 2017-05-27 17:44 +1000 |
| Message-ID | <2cnnvd-ub5.ln1@walter.foo> |
| In reply to | #110525 |
Groovy hepcat Patrick.Schluter was jivin' in comp.lang.c on Wed, 24 May
2017 4:16 pm. It's a cool scene! Dig it.
> Le 14.01.2017 à 13:16, Alla _ a écrit :
>> Hello!
I haven't seen the original post nor any followup except the one to
which I'm following up, so forgive me if this has already been covered.
>> Please, read my explanation before answering, to show
>> my mistake.
>> Honestly, for some time now I was sure I have no problems
>> with the statement sizeof(x) / sizeof(x[0]), usually used as
>> the macro to compute the size of an array of strings. I was
>> positive that I know how it works, and didn't doubt.
>> Somehow today when I used this macro again I've experienced
>> a confusion - how does it work, and what have I completely
>> forgotten? Although shameful, I have decided to come here again
>> for help on this matter.
It's unbelievably simple! The number of array elements can be
calculated as the total size of the array divided by the size of a
single element.
>> For example:
>> char *array[] = {"abc", "defg", "hijklmop", NULL};
>> The pointer points to an array that has 4 strings.
What pointer? There are 4 pointers here, all inside the array. It is
an array of pointer to char with 4 elements, after all. There is no
other pointer here.
>> sizeof(x) here will be sizeof(array) thus indicating
>> the size in bytes of the whole array of strings,
>> because 'array' here is used as the address of the
>> first sub-element, which is 'a' (array is the same as
>> array[0][0]);
What? That makes no sense at all! You're completely confused, Alla_.
>> so sizeof(array) will give the number of bytes occupied
>> by the whole array of strings, i.e. number
There is really no such thing as an array of strings. Why are people
often so confused by this concept? A string is really a data format,
not a type. It's a sequence of characters ending with a null character.
This can be stored in an array or a block of dynamically allocated
memory. A string literal is an (unnamed) array of char containing a
string.
An array could be an array of arrays (commonly called a 2 dimentional
array) of char containing strings. Alternatively, it could be an array
of pointers, each of which may point at (the first element of) an array
of char or dynamically allocated memory containing a string. Or it
could be an array of some other type.
>> of characters x 1 (which is the size of a char);
The size of an array is the size of a single element multiplied by the
number of elements. The size of an array such as the one named array in
the example above is, in bytes, sizeof (char *) multiplied by 4. The
expression sizeof array yields this value, while sizeof array[0] gives
the size of a single array element (char * in this case).
>> the denominator sizeof(x[0]) gives the size of the
>> first element of the array,
Right.
>> i.e. the size of the first
>> string, which is here "abc", so it it is 3 (3 characters,
Wrong! What is the type of your array? It's char *[4] (4 element array
of pointer to char), right? So what type is an element of this array?
It's char * (pointer to char), obviously.
>> each 1 byte); and all other strings have different
>> number of characters in them, and hence different
>> number of bytes;
>>
>> how then sizeof(x) / sizeof(x[0]) gives a correct number
>> of strings in the array (it actually does, I have tested it
It doesn't give the number of strings. It gives the number of array
elements. Forget about strings for the moment. The size of an array
divided by the size of one of its elements yields the number of
elements, regardless of the type of that element and the format of data
(string or otherwise) stored therein.
>> on different strings)? Please, show me my mistake.
>
> As other have explained, that macro falls apart when applied to a
> pointer instead of an array. Something that can happen quite easily.
Patrick, pointers don't come into the equation here. Alla_ is simply
confusing things. Though you are correct, it's irrelevant to the
question the OP has asked.
> The thing to do in practice and if you use gcc is to use an extension
No, the thing to do in practice is usually to try to write code as
portable as practical. There are situations in which portability will
not be practical, but this is not one of those situations.
> to make sure it is really an array and not a *. Here a macro inspired
> from the one used in Linux kernel
>
> #ifdef __GNUC__
> #define NUM_ELEMS(arr) (sizeof(struct {int
> :-!!(__builtin_types_compatible_p(typeof (arr), typeof
> (&0[arr])));})+sizeof arr/sizeof 0[arr])
Didn't you notice that you've broken a macro definition up into
multiple lines without a line concatination sequence? Apparently not.
> #else
> /* A portable variant, but which doesn't check for array or pointer.
> */
> #define NUM_ELEMS(arr) (sizeof arr/sizeof 0[arr])
> #endif
Ye gads!
> 2 remarks:
> 1 the 0[arr] is just a little trick so that one doesn't need the extra
> parenthesis around the macro parameter.
This is, IMO, unnecessary obfuscation.
> 2 sizeof arr also hasn't the parenthesis, this I did to enforce that
> the MACRO is not invoked with a type but with a array name.
And if someone uses, say, an expression such as NUM_ELEMS(somearray +
2)? The expansion will be (sizeof somearray + 2/sizeof 0[somearray +
2]), a legal expression that doesn't represent the number of elements
of somearray! It parses as (sizeof somearray + (2 / sizeof 0[somearray
+ 2])).
And the 0[arr] or even arr[0] expression would produce a diagnostic if
arr were a type name.
--
----- Dig the NEW and IMPROVED news sig!! -----
-------------- Shaggy was here! ---------------
Ain't I'm a dawg!!
[toc] | [prev] | [next] | [standalone]
| From | "Patrick.Schluter" <Patrick.Schluter@free.fr> |
|---|---|
| Date | 2017-05-28 13:52 +0200 |
| Message-ID | <592ab9f3$0$31632$426a74cc@news.free.fr> |
| In reply to | #110812 |
Le 27.05.2017 à 09:44, Peter "Shaggy" Haywood a écrit :
> Groovy hepcat Patrick.Schluter was jivin' in comp.lang.c on Wed, 24 May
> 2017 4:16 pm. It's a cool scene! Dig it.
>
>> Le 14.01.2017 à 13:16, Alla _ a écrit :
>>> Hello!
>
> I haven't seen the original post nor any followup except the one to
> which I'm following up, so forgive me if this has already been covered.
>
>>> Please, read my explanation before answering, to show
>>> my mistake.
>>> Honestly, for some time now I was sure I have no problems
>>> with the statement sizeof(x) / sizeof(x[0]), usually used as
>>> the macro to compute the size of an array of strings. I was
>>> positive that I know how it works, and didn't doubt.
>>> Somehow today when I used this macro again I've experienced
>>> a confusion - how does it work, and what have I completely
>>> forgotten? Although shameful, I have decided to come here again
>>> for help on this matter.
>
> It's unbelievably simple! The number of array elements can be
> calculated as the total size of the array divided by the size of a
> single element.
>
>>> For example:
>>> char *array[] = {"abc", "defg", "hijklmop", NULL};
>>> The pointer points to an array that has 4 strings.
>
> What pointer? There are 4 pointers here, all inside the array. It is
> an array of pointer to char with 4 elements, after all. There is no
> other pointer here.
>
>>> sizeof(x) here will be sizeof(array) thus indicating
>>> the size in bytes of the whole array of strings,
>>> because 'array' here is used as the address of the
>>> first sub-element, which is 'a' (array is the same as
>>> array[0][0]);
>
> What? That makes no sense at all! You're completely confused, Alla_.
>
>>> so sizeof(array) will give the number of bytes occupied
>>> by the whole array of strings, i.e. number
>
> There is really no such thing as an array of strings. Why are people
> often so confused by this concept? A string is really a data format,
> not a type. It's a sequence of characters ending with a null character.
> This can be stored in an array or a block of dynamically allocated
> memory. A string literal is an (unnamed) array of char containing a
> string.
> An array could be an array of arrays (commonly called a 2 dimentional
> array) of char containing strings. Alternatively, it could be an array
> of pointers, each of which may point at (the first element of) an array
> of char or dynamically allocated memory containing a string. Or it
> could be an array of some other type.
>
>>> of characters x 1 (which is the size of a char);
>
> The size of an array is the size of a single element multiplied by the
> number of elements. The size of an array such as the one named array in
> the example above is, in bytes, sizeof (char *) multiplied by 4. The
> expression sizeof array yields this value, while sizeof array[0] gives
> the size of a single array element (char * in this case).
>
>>> the denominator sizeof(x[0]) gives the size of the
>>> first element of the array,
>
> Right.
>
>>> i.e. the size of the first
>>> string, which is here "abc", so it it is 3 (3 characters,
>
> Wrong! What is the type of your array? It's char *[4] (4 element array
> of pointer to char), right? So what type is an element of this array?
> It's char * (pointer to char), obviously.
>
>>> each 1 byte); and all other strings have different
>>> number of characters in them, and hence different
>>> number of bytes;
>>>
>>> how then sizeof(x) / sizeof(x[0]) gives a correct number
>>> of strings in the array (it actually does, I have tested it
>
> It doesn't give the number of strings. It gives the number of array
> elements. Forget about strings for the moment. The size of an array
> divided by the size of one of its elements yields the number of
> elements, regardless of the type of that element and the format of data
> (string or otherwise) stored therein.
>
>>> on different strings)? Please, show me my mistake.
>>
>> As other have explained, that macro falls apart when applied to a
>> pointer instead of an array. Something that can happen quite easily.
>
> Patrick, pointers don't come into the equation here. Alla_ is simply
> confusing things. Though you are correct, it's irrelevant to the
> question the OP has asked.
No, it's not! (and we can do the Monty Pyton sketch to continuer :-)
>
>> The thing to do in practice and if you use gcc is to use an extension
>
> No, the thing to do in practice is usually to try to write code as
> portable as practical. There are situations in which portability will
> not be practical, but this is not one of those situations.
In practice, one has often to do with a foreign and big codebase one
doesn't (can't) know every corner of. Replacing the portable macro
x/x[0] by the implementation specific gnu thingy (when possible) can
have surprizing results. It happens sometimes that the code works
somehow not completely correctly but enough so that it doesn't blow in
your face directly. By using that macro (lifted from Linux kernel), an
error of the compiler will take care of you, because the unsavory thing
with the x/x[0] formula is that it compiles when x is a pointer and that
is very rarely what you want.
>
>> to make sure it is really an array and not a *. Here a macro inspired
>> from the one used in Linux kernel
>>
>> #ifdef __GNUC__
>> #define NUM_ELEMS(arr) (sizeof(struct {int
>> :-!!(__builtin_types_compatible_p(typeof (arr), typeof
>> (&0[arr])));})+sizeof arr/sizeof 0[arr])
>
> Didn't you notice that you've broken a macro definition up into
> multiple lines without a line concatination sequence? Apparently not.
>
>> #else
>> /* A portable variant, but which doesn't check for array or pointer.
>> */
>> #define NUM_ELEMS(arr) (sizeof arr/sizeof 0[arr])
>> #endif
>
> Ye gads!
>
>> 2 remarks:
>> 1 the 0[arr] is just a little trick so that one doesn't need the extra
>> parenthesis around the macro parameter.
>
> This is, IMO, unnecessary obfuscation.
>
>> 2 sizeof arr also hasn't the parenthesis, this I did to enforce that
>> the MACRO is not invoked with a type but with a array name.
>
> And if someone uses, say, an expression such as NUM_ELEMS(somearray +
> 2)? The expansion will be (sizeof somearray + 2/sizeof 0[somearray +
> 2]), a legal expression that doesn't represent the number of elements
> of somearray! It parses as (sizeof somearray + (2 / sizeof 0[somearray
> + 2])).
> And the 0[arr] or even arr[0] expression would produce a diagnostic if
> arr were a type name.
>
True, you're right. I will change that.
[toc] | [prev] | [next] | [standalone]
| From | "Peter \"Shaggy\" Haywood" <phaywood@alphalink.com.au> |
|---|---|
| Date | 2017-06-04 18:24 +1000 |
| Message-ID | <2msc0e-j06.ln1@walter.foo> |
| In reply to | #110817 |
Groovy hepcat Patrick.Schluter was jivin' in comp.lang.c on Sun, 28 May
2017 9:52 pm. It's a cool scene! Dig it.
> Le 27.05.2017 à 09:44, Peter "Shaggy" Haywood a écrit :
>> Groovy hepcat Patrick.Schluter was jivin' in comp.lang.c on Wed, 24
>> May 2017 4:16 pm. It's a cool scene! Dig it.
[Snip...]
>>> As other have explained, that macro falls apart when applied to a
>>> pointer instead of an array. Something that can happen quite easily.
>>
>> Patrick, pointers don't come into the equation here. Alla_ is
>> simply
>> confusing things. Though you are correct, it's irrelevant to the
>> question the OP has asked.
>
> No, it's not! (and we can do the Monty Pyton sketch to continuer :-)
The OP asked about determining the number of an array's elements by
dividing the size of the array by the size of an element. What do
pointers have to do with that?
>>> The thing to do in practice and if you use gcc is to use an
>>> extension
>>
>> No, the thing to do in practice is usually to try to write code as
>> portable as practical. There are situations in which portability will
>> not be practical, but this is not one of those situations.
>
> In practice, one has often to do with a foreign and big codebase one
> doesn't (can't) know every corner of. Replacing the portable macro
> x/x[0] by the implementation specific gnu thingy (when possible) can
> have surprizing results.
Yes, and more often than not in ways you don't want. It's better to
take the path of least surprise. If there's a bug, you don't find and
eradicate it by masking it with non-standard stuff.
> It happens sometimes that the code works
> somehow not completely correctly but enough so that it doesn't blow in
> your face directly.
And then blows up in the client's face after shipping, yeah!
> By using that macro (lifted from Linux kernel), an
> error of the compiler will take care of you, because the unsavory
> thing with the x/x[0] formula is that it compiles when x is a pointer
> and that is very rarely what you want.
So don't use it with a pointer. You wouldn't use it with an int, a
double, a char, an unsigned long, etc. Why use it with a pointer? I
can't see why anyone would use it with anything but an array, unless
they lack a basic understanding of C (which, yes, Alla_ obviously
does).
--
----- Dig the NEW and IMPROVED news sig!! -----
-------------- Shaggy was here! ---------------
Ain't I'm a dawg!!
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c
csiph-web