LINUX.ORG.RU

Знатокам ANSI C - по поводу размещения элементов массива в памяти


0

0

Допустим есть некоторый тип SomeType и массив из элементов такого типа: SomeType array[123]. Гарантированно ли что элементы в массиве располагаются последовательно без промежутков между ними? Иными словами, верно ли что:

((char *) array) + sizeof(SomeType) == array + 1

?

Перемещено cavia_porcellus из Talks

Deleted

Хм... А как оно оказалось в толксах? Постил в development =).

Deleted
()

Конечно, гарантировано. Иначе нафига нужны массивы?

array[2] = *(array + 2);

anonymous
()
Ответ на: комментарий от Deleted

Перечитал 3 раза...

> Гарантированно ли что элементы в массиве располагаются последовательно без промежутков между ними?

И вот ответ:

> array[2] = *(array + 2)

Это значит, что когда мы прибавляем к указателю число, по сути, содержащийся в нём адрес увеличивается на sizeof(тип_указателя).. Повтыкай ещё раз в арифметику указтелей..

anonymous
()

>Иными словами, верно ли что:

>((char *) array) + sizeof(SomeType) == array + 1 

...

if(((char *) array) + sizeof(SomeType) == array + 1 )
        printf("All correct!\n");

...

cPunk ★★
()
Ответ на: комментарий от Deleted

> А можете ткнуть меня в конкретный пункт в стандарте?

в стандарте С++ точно есть явная фраза. А в стандарте С это как минимум неявно видно в куче примеров.

Упомянутый alignment должен быть включен компилятором в sizeof

dilmah ★★★★★
()

Тогда при выравнивании всё ok

anonymous
()
Ответ на: комментарий от dilmah

>> Упомянутый alignment должен быть включен компилятором в sizeof

Ясно, спасибо =).

Deleted
()

НЕТ. Это НЕ ВЕРНО.

Есть дергнутые компилеры которые вставляют дополнительные промежутки элементами массива. В живую таких не встречал но об этом прямым текстом написано в документации к Oracle.

cvv ★★★★★
()
Ответ на: комментарий от Deleted

>> array[2] = *(array + 2);

>Это то очевидно. Ты перечитай первое сообщение.

напрасно. Вполне реальна ситуация:

sizeof(array[2]) != sizeof(*(array + 2));

cvv ★★★★★
()
Ответ на: комментарий от cvv

>> НЕТ. Это НЕ ВЕРНО.

>> Есть дергнутые компилеры которые вставляют дополнительные промежутки элементами массива. В живую таких не встречал но об этом прямым текстом написано в документации к Oracle.

Т.е. не верно только в кривых компиляторах или это всё таки стандарт не гарантирует?

Deleted
()
Ответ на: комментарий от Deleted

в С99:

EXAMPLE 2 Another use of the sizeof operator is to compute the number of elements in an array: sizeof array / sizeof array[0]

dilmah ★★★★★
()
Ответ на: комментарий от cvv

>Есть дергнутые компилеры которые вставляют дополнительные промежутки элементами массива.

как замечали уже, по стандарту С++ в массиве значения должны размещаться без промежутков, как это согласуется с вашим примером?

anonymous
()
Ответ на: комментарий от anonymous

>по стандарту С++

вопрос по С а не С++. как дела обстоят в С++ я не в курсе.

cvv ★★★★★
()
Ответ на: комментарий от Deleted

вобщем sizeof(array[0]) на всех компилерах возвращает расстояние между началами соседних элементов массива.

как согласуется со стандартом разлчие в размере элемента массива и размере типа этого элемента я не знаю. Я всегда пытаюсь писать без предположений о следовании компилером стандарта.

cvv ★★★★★
()
Ответ на: комментарий от cvv

> вобщем sizeof(array[0]) на всех компилерах возвращает расстояние между началами соседних элементов массива.

Но:

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand.

Размер определяется по типу. Значит sizeof(array[0]) == sizeof(T), где T -- тип на базе которого построен array.

dilmah ★★★★★
()
Ответ на: комментарий от cvv

>Есть дергнутые компилеры которые вставляют дополнительные промежутки элементами массива. В живую таких не встречал но об этом прямым текстом написано в документации к Oracle.

По стандарту элементы масссива всегда занимают последовательную область памяти, но компилер может алигнить элементы массива, что и делает например ГЦЦ с включенной оптимизацией.

Sidrian
()
Ответ на: комментарий от cvv

>напрасно. Вполне реальна ситуация:

>sizeof(array[2]) != sizeof(*(array + 2));

4.2

Sidrian
()

>Допустим есть некоторый тип SomeType и массив из элементов такого типа: SomeType array[123]. Гарантированно ли что элементы в массиве располагаются последовательно без промежутков между ними? Иными словами, верно ли что:

>((char *) array) + sizeof(SomeType) == array + 1

>?

Насколько я помню сконвертив в указатель на тип с лесс стрикт алигмент то единственное что ты можешь гарантировано сделать это кастануть его назад.

Sidrian
()
Ответ на: комментарий от Sidrian

>По стандарту элементы масссива всегда занимают последовательную область памяти

Значит я говорил о компилерах нарушающих стандарт.

когда ГЦЦ делает выравнивание он не нарушает стандарт - он выравнивает тип и дополнитьно выравнивать элементы массива ему не приходится.

cvv ★★★★★
()

А ведь если подумать, то окажется что если это утверждение не выполняется, то мы не имеем права сделать SomeType *array = malloc(n*sizeof(SomeType));. Так что стандарт обязан это гарантировать... Или я туплю под вечер?

Deleted
()
Ответ на: комментарий от Deleted

вот-вот. Именно это я и имел в виду под "в стандарте С это как минимум неявно видно в куче примеров".

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

еще там есть пример вычисления размера массива в виде sizeof(array)/sizeof(array[0]).

Но в стандарте написано что The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand.

Значит sizeof(array[0]) == sizeof(SomeType)

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

>еще там есть пример вычисления размера массива в виде sizeof(array)/sizeof(array[0]).

>Значит sizeof(array[0]) == sizeof(SomeType)

Не очень удачный пример, в том же с99 написано для sizeof:
When applied to an operand that has array type, the result is the total number of bytes in the array.
так что никто по идее не запрещает компилятору напихать для выравнивания каждого элемента еще пустых байтов, от этого верность того выражения не изменится и при этом будет sizeof(array[0]) != sizeof(SomeType).

koTuk
()
Ответ на: комментарий от koTuk

> и при этом будет sizeof(array[0]) != sizeof(SomeType).

пойнт был в том что sizeof(array[0]) == sizeof(SomeType) следует из фразы "The size is determined from the type of the operand." -- ведь array[0] имеет тип SomeType

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

>sizeof(array[0]) == sizeof(SomeType) следует из фразы "The size is determined from the type of the operand."
>ведь array[0] имеет тип SomeType

Ну и что с того ? Там написано что размер определяется из типа операнда, но только в одном случае операнд это array[0] а в другом SomeType, пусть даже и array[0] имеет тип SomeType.

koTuk
()
Ответ на: комментарий от koTuk

Нельзя создать массив из элементов, выравненных по границе, превышающей размер элемента. Если было бы можно - то либо вся адресная арифметика перестала работать (что есть бред), либо sizeof должен выдавать размер с учётом выравнивания (что есть неправильно)

Итого, нельзя создать массив с "дырками". И данные в массивах следуют "вплотную"

anonymous
()
Ответ на: комментарий от koTuk

> будет sizeof(array[0]) != sizeof(SomeType)

Изыди! Что за ерунда? Смотри:

array[10] equals to *(array + 10).

Так что ты написал выше... Ну ты сам понял..

anonymous
()

> Гарантированно ли что элементы в массиве располагаются
> последовательно без промежутков между ними?

Элементы - да, полезная информация - недъ. Из-за паддинга структура
 поимеет на 1 байт больше, чем инфы в ней: 

struct test {
    char cc [3];
    int qq [3];
};

int main (int argc, char * argv []) {
    int i;
    struct test a [10];

    printf ("%lu vs %lu\n", sizeof (struct test), 3 * sizeof (char) + 3 * sizeof (int));
    printf ("%lX vs %lX\n", ((char *) a) + sizeof (struct test), a + 1);
    for (i = 0; i < 10; i++) {
        printf ("0x%lX (%lu)\n", (unsigned long) &a [i], (unsigned long) &a [i]);
    }
    return 0;
}
-----------------------------------------------------------------
16 vs 15
BFF023F0 vs BFF023F0
0xBFF023E0 (3220186080)
0xBFF023F0 (3220186096)
0xBFF02400 (3220186112)
0xBFF02410 (3220186128)
0xBFF02420 (3220186144)
0xBFF02430 (3220186160)
0xBFF02440 (3220186176)
0xBFF02450 (3220186192)
0xBFF02460 (3220186208)
0xBFF02470 (3220186224)

anonymous
()
Ответ на: комментарий от anonymous

Причём паддинг не обязательно в конце структуры. В данном случае будед выравнено именно int qq [0], и поэтому лишний байт появится между char cc [2] и int qq [0];

anonymous
()
Ответ на: комментарий от anonymous

Не надо путать теплое с мягким
sizeof(array[0]) != sizeof(SomeType)
не противоречит тому чтобы выполнялось
array[10] equals to *(array + 10)

koTuk
()
Ответ на: комментарий от anonymous

Про sizeof и выравнивание в структурах четко прописано в с99 так что можно было не напрягаться :)

When applied to an operand that has structure or union type, the result is the total number of bytes in such an object, including internal and trailing padding.

koTuk
()
Ответ на: комментарий от koTuk

>Ну и что с того ? Там написано что размер определяется из типа операнда, но только в одном случае операнд это array[0] а в другом SomeType, пусть даже и array[0] имеет тип SomeType.

Котик, ты жжешь напалмом. Представь что есть функция "void f(SomeType *a);" и есть переменные "SomeType a[10], b;". По твоему a[0] и b могут иметь разные размеры. Вопрос: как тогда работают вызовы "f(a); f(&b);"?

Sidrian
()
Ответ на: комментарий от Sidrian

А лучше даже функция "void f(SomeType a)", что-бы требовалось выделить на стеке sizeof(SomeType) места для передачи параметра, а не указателя на него.

Sidrian
()
Ответ на: комментарий от Sidrian

Так в чем проблема ? Отбросит trailing padding - размещение в внутри типа у элемента массива мменять нет смысла. Собственно вопрос и был как раз в этом
>Гарантированно ли что элементы в массиве располагаются последовательно без промежутков между ними?

koTuk
()

Да, гарантировано.

anonymous
()
Ответ на: комментарий от koTuk

> sizeof(array[0]) != sizeof(SomeType)
> не противоречит тому чтобы выполнялось

> array[10] equals to *(array + 10)


И ты можешь привести пример такого?

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

>И ты можешь привести пример такого?

Повторяю - я не пишу стандарты, дело не во мне. Приведи выдержку из стандарта где сказано что такого не может быть.

koTuk
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.