LINUX.ORG.RU

Присвоение массивов в Си

 


0

1

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

То есть почему нельзя сделать так:

int a[10];
int b[10];
a = b;

Однако, если обернуть всё в структуру, то можно так:

struct {int array[10]; } a, b;
a = b;

Сломалось ли бы что-то в языке, если бы присвоение массивов a = b работало как условный memcpy(a, b, sizeof(b)) ?

★★★★★

Сишные массивы - промежуточная форма между указателями и полноценными структурами данных. ЕМНИП, в ранних версиях их и не было, было что-то в духе «int *a = alloca(size);». Потом ввели понятие массива, но не доделали, как и почти всё в си. Отсюда и decay, и эти приколы.

anonymous
()

В приведённом ответе дан ответ, почему это нельзя сделать с точки зрения существующих правил, но не почему нельзя эта правила изменить. Вариант с memcpy однозначно не подходит, потому что в отличие от других языков в Си ни одна языковая конструкция не может быть преобразована в вызов функции. Копирование и возврат статических массивов небольших массивов в принципе, может быть реализован без вызова функции, но тут вопрос в implementation limits, видимо комитет решил не заморачиваться.

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

в отличие от других языков в Си ни одна языковая конструкция не может быть преобразована в вызов функции

В каком смысле?

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

Всё я прекрасно знаю. В Си, в отличие от C++/D/C# языковые конструкции не переписываются в вызовы функции. Если написано a+b, то это a+b, а не скрытый вызов функции a.opAdd(b). В примере по ссылке приведена замена копирования структуры на memcpy в целях оптимизации, но это - «исключение, которое подтверждает правило». Пожалуй, это правило нарушается только в одном случае - компиляторы Си иногда действительно переписывают копирование больших структур, но это не совсем про язык, а про оптимизацию, которая может зависеть от версии языка и от опций компиляции.

mxfm ★★
()
Последнее исправление: mxfm (всего исправлений: 1)
Ответ на: комментарий от mxfm

Вариант с memcpy однозначно не подходит, потому что в отличие от других языков в Си ни одна языковая конструкция не может быть преобразована в вызов функции.

Сомневаюсь, что такое вот («ни одна языковая конструкция не может быть преобразована в вызов функции») написано в стандарте. Как по-вашему копирование структур происходит?

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

Мог бы прямую ссылку на ответ дать xD

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

Почитал ответы, прошёл по ссылкам, но вопросы остались. Смущает вот это вот:

In the first ANSI C standard in 1989 they added the ability to copy structs by value ... But it was far too late to go back and change the meaning of a = b; to copy arrays by value, too much code was written that already depends on The Rule.

Не очень понятно, какой код сломался бы, ведь сейчас a = b — просто ошибка компиляции.

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

Не очень понятно, какой код сломался бы

Может такой код имелся ввиду: https://godbolt.org/z/1enPnGWqh

Некоторые пишут массивы в аргументах функции, а не указатели, хотя по факту это указатели, и эти массивы только запутывают…

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

Не там, а тут:

Прочитайте ветку с начала ещё раз.

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

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

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

Оригинальный вопрос был: «почему a = b для массивов не ведёт себя как memcpy(a, b, sizeof(b)) подобно тому, как это работает для структур?»

А теперь расскажите, где тут должно поломаться освобождение памяти?

Waterlaz ★★★★★
() автор топика
Последнее исправление: Waterlaz (всего исправлений: 1)
Ответ на: комментарий от mxfm

не имеет отношения к выделению динамической памяти

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

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

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

встроенное выделение-высвобождение

Это ещё что такое? //_-)

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

Действительно, такое явно не написано в стандарте, но это логически следует из характера языка Си.

Я давно копался в листинге программ. Насколько я знаю, копирование структур небольшой длинны происходит средствами ассемблера, копирование больших структур - с целью оптимизации вызовом специальных функций копирования, некоторые из которых написаны на ассемблере с использованием расширений языка или задействованием процессорных инструкций по работе с регистрами для хранения больших данных. Использование этих оптимизаций зависит от версии компилятора, контекста программы и опций компиляции.

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

Вы сказали, что память будет утекать.

Ага! Щаз! Процитируй, граматей.

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

Дело не в sizeof.

Автор спросил, почему не разрешить код типа

int a[10];

int b[10];

a = b;

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

mxfm ★★
()
Последнее исправление: mxfm (всего исправлений: 1)
Ответ на: комментарий от mxfm

Автор спросил, почему не разрешить код типа

Ежели разрешить компиляцию этого г, то при высвобождении будя segment fault. Ещё вопросы?

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

Ежели разрешить компиляцию этого г, то при высвобождении будя segment fault. Ещё вопросы?

Нет, не будет. С чего ему быть?

mxfm ★★
()

ТС слишком простой пример привел.
Структуры могут иметь и адресные поля … … …

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

Получается, ты не знаешь. Код:

int a[10];

int b[10];

a = b;

Если заменить a=b на memcpy (и добавить инициализатор для a) совершенно валиден. Объекты ‘a’ и ‘b’ - массивы, память для которых выделена автоматически (в стеке), потому копирование этих массивов возможно. Ты наверное спутал этот код с кодом

int *p;

memcpy(p, …);

в котором действительно будет segfault. Вобщем, зря ты написал свои комментарии и хвастался знанием Си.

mxfm ★★
()

Возвращаясь к вопросу. Я нашёл вот эту информацию http://c-faq.com/struct/firstclass.html

Возможно, на тот момент времени запрет на операции с массивами постоянного размера был вызван теми же соображениями, что и запрет на операции со структурами, который позднее убрали - различия в implementation details, которые по состоянию на 2022 год уже никто не помнит.

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

А где ты здесь memcpy увидел, умник? У-ха-ха. :)))

Ты говоришь, что если его поставить, то будет segfault или «ошибка при высвобождении памяти», что 100% неверно.

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

А где ты здесь memcpy увидел, умник? У-ха-ха. :)))

Это такой троллинг толстый или вы таки не способны перечитать вопрос топика?

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

вопрос топика?

Вот именно, вот именно… Здесь он и будет похоронен… :)

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

Я говорю, что не удастся это г скомпилировать, а ежели удастся, то… :)

Эту глупость вы уже который раз повторяете, а прочитать вопрос не в состоянии

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

Эту глупость вы уже который раз повторяете, а прочитать вопрос не в состоянии

Он похоже, просто троллит …

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

просто троллит …

А что остаётся делать, когда народ начинает играться в безумные «хотелки»? Вообще не думая.

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

А что остаётся делать, когда народ начинает играться в безумные «хотелки»? Вообще не думая.

Неубедительно. Мы все тут ожидаем пример, где память утечёт или приложение упадёт.

Waterlaz ★★★★★
() автор топика

Возвращаясь к вопросу, после некоторых размышлений думаю так. В принципе, копирование массивов могло было быть реализовано также, как и структур, с теми же ограничениями на implementation limits и details, что и к структурам. Я не вижу технических причин для разрешения копирования структур, но ограничения для массивов постоянного размера.

С другой стороны, при увеличении размера структуры/массива становится целесообразно простое копирование заменить вызовом функции с целью оптимизации. Однако, поскольку в Си замена языковых конструкций вызовами функции не свойственна, то это было бы нарушением «смысла и духа» языка. Другими словами, если вам нужна замена a+b на вызов функции, это был бы уже не Си, а С++.

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

Мы все тут ожидаем пример

Ты упустил важную деталь. Для начала оно должно скомпилироваться. У-ха-ха. :)))

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

Я думаю, что тут как раз правильный ответ Присвоение массивов в Си (комментарий)

В примере от @fsb4000 int a[10] при передаче в функцию работают как указатели.

void test(int a[10], int b[10])
{
    a = b;
}

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

Тут a и b по сути указатели, что не отменяет возможности копировать массив, если это действительно массив. Впрочем, тогда бы ситуация с возвратом зависела бы от того, где объект определён - внутри функции или в параметрах.

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