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


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

sizeof(x) / sizeof(x[0])

Started byAlla _ <modelling.data@gmail.com>
First post2017-01-14 04:16 -0800
Last post2017-01-15 12:55 -0800
Articles 7 on this page of 27 — 10 participants

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


Contents

  sizeof(x) / sizeof(x[0]) Alla _ <modelling.data@gmail.com> - 2017-01-14 04:16 -0800
    Re: sizeof(x) / sizeof(x[0]) "Fernando D. Bozzo" <fdbozzo@gmail.com> - 2017-01-14 04:27 -0800
      Re: sizeof(x) / sizeof(x[0]) Alla _ <modelling.data@gmail.com> - 2017-01-14 04:43 -0800
        Re: sizeof(x) / sizeof(x[0]) "Fernando D. Bozzo" <fdbozzo@gmail.com> - 2017-01-14 04:52 -0800
          Re: sizeof(x) / sizeof(x[0]) Alla _ <modelling.data@gmail.com> - 2017-01-14 06:10 -0800
          Re: sizeof(x) / sizeof(x[0]) Keith Thompson <kst-u@mib.org> - 2017-01-14 15:55 -0800
    Re: sizeof(x) / sizeof(x[0]) jt@toerring.de (Jens Thoms Toerring) - 2017-01-14 13:13 +0000
      Re: sizeof(x) / sizeof(x[0]) Alla _ <modelling.data@gmail.com> - 2017-01-15 22:23 -0800
        Re: sizeof(x) / sizeof(x[0]) Keith Thompson <kst-u@mib.org> - 2017-01-16 08:58 -0800
    Re: sizeof(x) / sizeof(x[0]) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-01-14 14:47 +0000
      Re: sizeof(x) / sizeof(x[0]) Alla _ <modelling.data@gmail.com> - 2017-01-14 07:17 -0800
    Re: sizeof(x) / sizeof(x[0]) Manfred <noname@invalid.add> - 2017-01-14 16:22 +0100
    Re: sizeof(x) / sizeof(x[0]) Barry Schwarz <schwarzb@dqel.com> - 2017-01-14 08:35 -0800
      Re: sizeof(x) / sizeof(x[0]) Alla _ <modelling.data@gmail.com> - 2017-01-15 22:53 -0800
        Re: sizeof(x) / sizeof(x[0]) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-01-16 15:58 +0000
          Re: sizeof(x) / sizeof(x[0]) Alla _ <modelling.data@gmail.com> - 2017-01-16 22:38 -0800
            Re: sizeof(x) / sizeof(x[0]) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-01-17 10:11 +0000
    Re: sizeof(x) / sizeof(x[0]) James Kuyper <jameskuyper@verizon.net> - 2017-01-14 11:43 -0500
      Re: sizeof(x) / sizeof(x[0]) Keith Thompson <kst-u@mib.org> - 2017-01-14 16:01 -0800
      Re: sizeof(x) / sizeof(x[0]) Alla _ <modelling.data@gmail.com> - 2017-01-16 01:36 -0800
        Re: sizeof(x) / sizeof(x[0]) Barry Schwarz <schwarzb@dqel.com> - 2017-01-16 09:47 -0800
        Re: sizeof(x) / sizeof(x[0]) James Kuyper <jameskuyper@verizon.net> - 2017-01-16 21:12 -0500
          Re: sizeof(x) / sizeof(x[0]) Alla _ <modelling.data@gmail.com> - 2017-01-16 22:29 -0800
    Re: sizeof(x) / sizeof(x[0]) Les Cargill <lcargill99@comcast.com> - 2017-01-14 14:27 -0600
    Re: sizeof(x) / sizeof(x[0]) Keith Thompson <kst-u@mib.org> - 2017-01-14 15:52 -0800
    Re: sizeof(x) / sizeof(x[0]) Lőrinczy Zsigmond <nospam@for.me> - 2017-01-15 20:20 +0100
      Re: sizeof(x) / sizeof(x[0]) Keith Thompson <kst-u@mib.org> - 2017-01-15 12:55 -0800

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


#101994

FromBarry Schwarz <schwarzb@dqel.com>
Date2017-01-16 09:47 -0800
Message-ID<oe1q7c1ph50u9oovdtilf6lfttsa180gqh@4ax.com>
In reply to#101941
On Mon, 16 Jan 2017 01:36:20 -0800 (PST), Alla _
<modelling.data@gmail.com> wrote:

>Thank you for this interesting explanation. I would like to ask for a bit
>clarification, if I may: 
>char __unnamed1[] = {'H', 'e', 'l', 'l', 'o', ' ', '\0'};
>char char_array[sizeof __unnamed1];
> char char_array[] = {'H', 'e', 'l', 'l', 'o', ' ', '\0'};
>Do I understand correctly that you can say the same thing about 
>char _unnamed1[]? I don't see how it differs from char _char_array[],
>when same literals are assigned to them, like in this case  {'H', 'e', 'l', 'l', 'o', ' ', '\0'}?

You are treating his example as if it were executable C code.  It
isn't.  He was providing a **conceptual** model of how the
initialization is performed.  It is unlikely that initialization would
actually call strcpy.  If you don't invoke strcpy yourself, that
function will probably not be included in your executable program.

The whole point of the responses is you were confusing an array of
pointers with the things the pointers pointed to.  Ben's example with
addresses and types may help you understand it better.

-- 
Remove del for email

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


#102019

FromJames Kuyper <jameskuyper@verizon.net>
Date2017-01-16 21:12 -0500
Message-ID<o5juej$7f7$1@dont-email.me>
In reply to#101941
On 01/16/2017 04:36 AM, Alla _ wrote:
> On Saturday, January 14, 2017 at 7:43:21 PM UTC+3, James Kuyper wrote:
...
>> In C, a string is not a data type, it is a data format. You cannot
>> declare a string. There's two things that people often think of then
>> they think they're declaring a string:
>>
>>     char char_array[] = "Hello ";
>>     char *char_ptr = "world!\n";
>>
>> "Hello " and "world!\n" are string literals. They cause the creation of
>> an unnamed char array of sufficient length to be initialized with the
>> specified characters, including a terminating null character. As a
>> result, those arrays do contain strings. In most contexts, a string
>> literal is automatically converted into a pointer to the first element
>> of that array. The initialization of an array of character type (such as
>> char_array above) is NOT one of those contexts. What the standard
>> actually says about such things makes those definitions equivalent (if
>> char_array has automatic storage duration) to the following code:
>>
>>     char __unnamed1[] = {'H', 'e', 'l', 'l', 'o', ' ', '\0'};
>>     char char_array[sizeof __unnamed1];
>>     memcpy(char_array, _unnamed1, sizeof __unnamed1);
>>
>>     char __unnamed2[] = {'W', 'o', 'r', 'l', 'd', '!', '\n', '\0'};
>>     char *char_ptr = unnamed2;
>>
>> The equivalence breaks down for arrays with file scope, which provides
>> no location for the memcpy() call, or for local arrays with static
>> storage duration, where the memcpy() call should only occur once, before
>> the start of the program. As described by the standard, the copy still
>> occurs in those cases, there's just no strictly conforming C code that
>> has exactly equivalent behavior.
>> Note that there is no way for a strictly conforming program to determine
>> whether or not __unnamed1 even exists. As a result, if char_array has
>> static storage duration, removing __unnamed1 and just initializing
>> char_array directly is a common optimization:
>>
>>      char char_array[] = {'H', 'e', 'l', 'l', 'o', ' ', '\0'};
>>
>> So, char_array is an array of char which can (but doesn't have to)
>> contain a string, while char_ptr is a pointer to char which can (but
>> doesn't have to) point at a string. Neither of those is a string itself.
>>
> Thank you for this interesting explanation. I would like to ask for a bit
> clarification, if I may: 
> char __unnamed1[] = {'H', 'e', 'l', 'l', 'o', ' ', '\0'};
> char char_array[sizeof __unnamed1];
>  char char_array[] = {'H', 'e', 'l', 'l', 'o', ' ', '\0'};
> Do I understand correctly that you can say the same thing about 
> char _unnamed1[]? I don't see how it differs from char _char_array[],
> when same literals are assigned to them, like in this case  {'H', 'e', 'l', 'l', 'o', ' ', '\0'}?

My point is that

    char  char_array[] = "Hello ";

has behavior that is described by the standard in terms of having two
different arrays. On is the unnamed array associated with the string
literal "Hello ", and the other is array named char_array. The standard
describes the initialization of char_array in terms of a copy from the
unnamed array.

On the other hand, if you had instead written:

    char char_array[] = {'H', 'e', 'l', 'l', 'o', ' ', '\0'};

the standard describes the initialization in terms of a single array,
each element of which must be initialized by the corresponding
expression in the initializer list.

In practice, that distinction is meaningless. You cannot write strictly
conforming code that can determine whether or not the array associated
with the string literal actually exists, distinct from the array that it
initializes. An implementation is free to use any method of initializing
char_array that has the same observable behavior, which is the same
behavior in both cases.
In practice, I'd expect that a separate array containing the initial
values would be used whenever the array has automatic storage duration.
I would expect the separate array to be optimized away when the array
has static storage duration. Of course, implementations are under no
obligation to meet my expectations.

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


#102020

FromAlla _ <modelling.data@gmail.com>
Date2017-01-16 22:29 -0800
Message-ID<c5dd8d8d-350b-40c6-b405-69d15e99038c@googlegroups.com>
In reply to#102019
On Tuesday, January 17, 2017 at 5:12:11 AM UTC+3, James Kuyper wrote:
> On 01/16/2017 04:36 AM, Alla _ wrote:
> > On Saturday, January 14, 2017 at 7:43:21 PM UTC+3, James Kuyper wrote:
> ...
> >> In C, a string is not a data type, it is a data format. You cannot
> >> declare a string. There's two things that people often think of then
> >> they think they're declaring a string:
> >>
> >>     char char_array[] = "Hello ";
> >>     char *char_ptr = "world!\n";
> >>
> >> "Hello " and "world!\n" are string literals. They cause the creation of
> >> an unnamed char array of sufficient length to be initialized with the
> >> specified characters, including a terminating null character. As a
> >> result, those arrays do contain strings. In most contexts, a string
> >> literal is automatically converted into a pointer to the first element
> >> of that array. The initialization of an array of character type (such as
> >> char_array above) is NOT one of those contexts. What the standard
> >> actually says about such things makes those definitions equivalent (if
> >> char_array has automatic storage duration) to the following code:
> >>
> >>     char __unnamed1[] = {'H', 'e', 'l', 'l', 'o', ' ', '\0'};
> >>     char char_array[sizeof __unnamed1];
> >>     memcpy(char_array, _unnamed1, sizeof __unnamed1);
> >>
> >>     char __unnamed2[] = {'W', 'o', 'r', 'l', 'd', '!', '\n', '\0'};
> >>     char *char_ptr = unnamed2;
> >>
> >> The equivalence breaks down for arrays with file scope, which provides
> >> no location for the memcpy() call, or for local arrays with static
> >> storage duration, where the memcpy() call should only occur once, before
> >> the start of the program. As described by the standard, the copy still
> >> occurs in those cases, there's just no strictly conforming C code that
> >> has exactly equivalent behavior.
> >> Note that there is no way for a strictly conforming program to determine
> >> whether or not __unnamed1 even exists. As a result, if char_array has
> >> static storage duration, removing __unnamed1 and just initializing
> >> char_array directly is a common optimization:
> >>
> >>      char char_array[] = {'H', 'e', 'l', 'l', 'o', ' ', '\0'};
> >>
> >> So, char_array is an array of char which can (but doesn't have to)
> >> contain a string, while char_ptr is a pointer to char which can (but
> >> doesn't have to) point at a string. Neither of those is a string itself.
> >>
> > Thank you for this interesting explanation. I would like to ask for a bit
> > clarification, if I may: 
> > char __unnamed1[] = {'H', 'e', 'l', 'l', 'o', ' ', '\0'};
> > char char_array[sizeof __unnamed1];
> >  char char_array[] = {'H', 'e', 'l', 'l', 'o', ' ', '\0'};
> > Do I understand correctly that you can say the same thing about 
> > char _unnamed1[]? I don't see how it differs from char _char_array[],
> > when same literals are assigned to them, like in this case  {'H', 'e', 'l', 'l', 'o', ' ', '\0'}?
> 
> My point is that
> 
>     char  char_array[] = "Hello ";
> 
> has behavior that is described by the standard in terms of having two
> different arrays. On is the unnamed array associated with the string
> literal "Hello ", and the other is array named char_array. The standard
> describes the initialization of char_array in terms of a copy from the
> unnamed array.
> 
It is clear now. Thank you, and thank you everyone for your explanations. 
> On the other hand, if you had instead written:
> 
>     char char_array[] = {'H', 'e', 'l', 'l', 'o', ' ', '\0'};
> 
> the standard describes the initialization in terms of a single array,
> each element of which must be initialized by the corresponding
> expression in the initializer list.
> 
> In practice, that distinction is meaningless. You cannot write strictly
> conforming code that can determine whether or not the array associated
> with the string literal actually exists, distinct from the array that it
> initializes. An implementation is free to use any method of initializing
> char_array that has the same observable behavior, which is the same
> behavior in both cases.
> In practice, I'd expect that a separate array containing the initial
> values would be used whenever the array has automatic storage duration.
> I would expect the separate array to be optimized away when the array
> has static storage duration. Of course, implementations are under no
> obligation to meet my expectations.

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


#101800

FromLes Cargill <lcargill99@comcast.com>
Date2017-01-14 14:27 -0600
Message-ID<o5e1e1$19d$1@dont-email.me>
In reply to#101737
Alla _ wrote:
> 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);
>


Assume 4-byte pointers.

sizeof(array) is then 16 - 4*4.
sizeof(array[0]) is 4
sizeof(array[0][0]) is 1 - sizeof(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,

C strings don't really have a size, they have a length.

A char array that contains a string may have a size, but
the way you've declared things the size is lost information.

So if you can get to a debugger or write a dump routine. look
at how things are laid out in memory and all will be revealed.

> each 1 byte); and all other strings have different
> number of characters in them, and hence different
> number of bytes;
>

You can get to the length of each string by using strlen().

> 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.
>
> Thank you!
>

l
-- 
Les Cargill

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


#101827

FromKeith Thompson <kst-u@mib.org>
Date2017-01-14 15:52 -0800
Message-ID<ln8tqdi4hd.fsf@kst-u.example.com>
In reply to#101737
Alla _ <modelling.data@gmail.com> writes:
[...]
> char *array[] = {"abc", "defg", "hijklmop", NULL};

`array` is a 4-element array of char* pointers.  (This would be easier
to talk about if it had a name other than "array".  I'll use backticks
to keep things straight.)

> The pointer points to an array that has 4 strings. 

What pointer?  `array` is an array object, not a pointer object.
(When used in an expression, the name does decay to a pointer value
in some but not all contexts, but that's not relevant here; the
operand of `sizeof` is one of the contexts in which that conversion
does not occur.)

It is not an "array of strings".  Strictly speaking, there is no such
thing as an "array of strings", since "string" is not a type.  It is an
array of 4 char* pointers.  The first 3 of those pointers happen to be
pointers to strings; the last is not, since it's a null pointer.

`array` does not contain strings.  It contains pointers to strings (plus
one pointer that isn't a pointer to a string).  But that's not relevant
to how `sizeof` works.

See N1570 7.1.1p1 for the definitions of "string" and "pointer to
string".

> sizeof(x) here will be sizeof(array) thus indicating 
> the size in bytes of the whole array of strings, 

This is the first time you've mentioned "x".  I guess you have a macro
whose definition you haven't shown us.  Most likely the macro is
something like this:

    #define ARRAY_LENGTH(x) (sizeof (x) / sizeof (x)[0])

invoked as

    ARRAY_LENGTH(array)

(I used extra parentheses that I wouldn't have used outside a macro
definition.)

> because 'array' here is used as the address of the
> first sub-element, which is 'a' (array is the same as
> array[0][0]); 

No, `array` in `sizeof(array)` is not being used as an address.
It's being used as the name of an object.  And no, `array` is not 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);

`sizeof(array)` is the number of bytes occupied by the array object.
It is 4 * sizeof (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;

Not at all.  `sizeof (x[0])`, which expands to `sizeof (array[0])`,
is the size of the first element of the array, which is a pointer
object.  (It's likely to be 8 on a 64-bit system.)  It has nothing
to do with the length of the string to which `array[0]` happens
to point.

> 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. 

It gives the number of pointer objects in the object `array`, which is
an array of `char*` pointers.  If `sizeof (char*) == 8`, then `sizeof
(array)` is 32, and `sizeof (array[0])` is 8, so `ARRAY_LENGTH(array)`
is 4.

(And of course the ARRAY_LENGTH() macro won't work with a pointer object,
even if that pointer object is a parameter defined with array notation.)

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

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


#101864

FromLőrinczy Zsigmond <nospam@for.me>
Date2017-01-15 20:20 +0100
Message-ID<o5gi14$q54$1@gioia.aioe.org>
In reply to#101737
This snippet from gdb might be relevant:

(gdb) print sizeof("ABCDEF")
$5 = 7

(gdb) print sizeof((char *)"ABCDEF")
$6 = 4

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


#101882

FromKeith Thompson <kst-u@mib.org>
Date2017-01-15 12:55 -0800
Message-ID<lneg04gi01.fsf@kst-u.example.com>
In reply to#101864
Lőrinczy Zsigmond <nospam@for.me> writes:
> This snippet from gdb might be relevant:
>
> (gdb) print sizeof("ABCDEF")
> $5 = 7
>
> (gdb) print sizeof((char *)"ABCDEF")
> $6 = 4

A snippet of output from a C program would be more relevant.
gdb's evaluation of C expression isn't necessarily 100% reliable,
though it's correct in this case.

#include <stdio.h>
int main(void) {
    printf("%zu\n", sizeof "ABCDEF");
    printf("%zu\n", sizeof ((char*)"ABCDEF"));
}

output:
7
8

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [standalone]


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

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


csiph-web