LINUX.ORG.RU

100500-й вопрос по realloc

 ,


0

1

почему в С98 и С++ realloc() пытается расширить текущий блок, и лишь в случае неудачи выделяет память на новом месте а в С99 — сразу выделяет память на новом месте?

★★★★★

Последнее исправление: cetjs2 (всего исправлений: 1)

Почему ты думаешь что он работает так? Поведение реаллока не специфицировано.

$ clang test.c -o test -std=c89
$ ./test
p1: 0x7ff23a403980, p2: 0x7ff23a403990
$ clang test.c -o test -std=c99
$ ./test
p1: 0x7fb329403980, p2: 0x7fb329403990
$ cat test.c
#include <stdio.h>
#include <stdlib.h>

int main()
{
	void *p1 = malloc(10);
	void *p2 = realloc(p1, 20);

	printf("p1: %p, p2: %p\n", p1, p2);
}
AptGet ★★★
()
Ответ на: комментарий от anonymous

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

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

он может удалить, затем пересоздать на том же месте

в случае С98/С++ он может не найти свободное место для блока

и выделить в совсем другом блоке

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

Таки что за C98? Я что-то пропустил, или в 98 вышел стандарт C?

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

в случае С98/С++ он может не найти свободное место для блока

и выделить в совсем другом блоке

еще от аллокатора зависит. brk использует или mmap анонимный. ну и надо зафрагментировать кучу.

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

По мне так тоже, нормальная имплементация сделает по стандарту posix.

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

и что этот тест покажет?

okay, допустим расширить не удалось

$ clang test.c -o test -std=c99
$ ./test
p1: 0x7f85ca801200, p2: 0x7f85ca801200

$ clang test.c -o test -std=c89
$ ./test
p1: 0x7fda29801200, p2: 0x7fda29801200

$ cat test.c
#include <stdio.h>
#include <stdlib.h>

int main()
{
	void *p1 = malloc(50000);
	void *p2 = realloc(p1, 50005);

	printf("p1: %p, p2: %p\n", p1, p2);
}

А вот пример с тем же блоком.

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

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

unt1tled ★★★★
()

Вообще лучше в таких вбросах давать ссылки на оба стандарта си и (в случае войны) еще и на posix всех версий, на которые, если что, ссылаются источники. Тут таки не talks.

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

граммарнаци идут в топку, читают c-faq и заново учат стандарт. в C99 return 0 в main опционален, int main() != int main(void) и 100%но корректно.

AptGet ★★★
()

Тебе это ничего не даст, если он выделяет новый блок после удаления( а судя по тестам пацанов так оно и есть) его семантика абсалютно не меняется.

Это не имеет смысла, а почему делают изменения(причем пруфцов нет) которые не имеют смысла знают только те, кто делают эти изменения. Возможно чтобы после прочтения мануала никто даже не мыслил о валидных указателях, после реалока.

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

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

ну и надо зафрагментировать кучу.

Не имеет смысла, за куском место либо есть, либо его нет. Если его нет, то оба поведут себя одинакого, если же оно есть - оно есть итак.

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

Какбэ предпочтения тут не важны.

Синтаксически функция с пустым аргументом в сишке - это f(void){}, поэтому такая запись априори логичней, чем f(){}, которая двусмысленна и не совсем логична.

Тоже самое с ++i, да и много с чем. Конечно все на это кладут, но какбэ это не ок.

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

В этом и состоял мой камент. Если понимаешь, что делаешь, никаких двусмысленностей быть не должно. Кстати,

return ++i;
или
return i++;
иногда играет роль.

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

Явных и на пустом месте, да - не делаешь. А так покласть, всякие нюансы ЯП дают профиты и эти профиты важнее каких-либо фобий или «не должно».

Вот когда оно играет роль - имеет смысл юзать i++, а когда не имеет - не имеет. Когда играет роль f() - имеет смысл юзать, а когда не имеет - не имеет.

Хотя лично у меня когда я пишу в kdevelop'е неслабо бомбит от того, что запильщики kdevelop'а поклали на этот нюанс и автокомплить не срабатывает нормально. С/С++ бич нашего времени.

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

Сишный продакшен выглядит не особо лучше этого - там и не такое пишут, просто это избитый и не имеющий смысла пример.

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

return 0 в main всегда был опционален, но чем же «int main() != int main(void)»?

я неправ, не равно только для объявлений, для определений равно.

int main(void) в любом случае легален тоже.

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

всякие нюансы ЯП дают профиты и эти профиты важнее каких-либо фобий или «не должно».

А вот тут начинает бомбить у меня :)

На C#, к примеру, можно запилить обход exception путем парсинга сообщения этого эксепшена и игнорирования данной строки. Когда ексепшен происходит в библиотеке, к коду которой доступа нет, это вроде как единственное решение, а воротит неподетски.

Получается профит ЯП, но ведь нельзя так.

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

я неправ, не равно только для объявлений, для определений равно.

Похоже все сложнее, в стандарте есть дыра для поддержки функций в стиле K&R и gcc считает определения функций без параметров именно такими.

~> gcc test10.c -o test10 -Wall -Wextra -std=c1x
~> cat test10.c
void a()
{
}

int main() 
{
	a(10, 20, 30);
}

clang дает warning.

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

Тебе это ничего не даст

Если это правда, то от realloc() версии С99 нет толка, а от С98/С++ есть

причем пруфцов нет

Сказал же: Гербердт Шилдт, справочник программиста 3-е издание, страница 221, русскоязычная версия. Нет основания считать, что переведена не верна: там явно делается акцент на то, что realloc() С++ и С99 работают по разному

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

скорость

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

Если это правда, то от realloc() версии С99 нет толка, а от С98/С++ есть

Это почему ещё? С чего ты сделал такой вывод? Судя по тестам поцанов оно таки расширят.

Сказал же: Гербердт Шилдт, справочник программиста 3-е издание, страница 221, русскоязычная версия. Нет основания считать, что переведена не верна: там явно делается акцент на то, что realloc() С++ и С99 работают по разному

Ну это какбэ не пруфец. Вычислить это не реально, а ссылки на стандарт он похоже не привёл.

скорость

Реалок и скорость понятия не совместимые. Если ты имеешь ввиду скорость посравнению с с89 реалоком?

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

Это почему ещё? С чего ты сделал такой вывод? Судя по тестам поцанов оно таки расширят.

я же сказал: если правда, сказанное Шилдтом

Вычислить это не реально, а ссылки на стандарт он похоже не привёл.

вообще не видел ни в одной книге пачки ссылок на стандарт

Если ты имеешь ввиду скорость посравнению с с89 реалоком?

по моим тестам реаллок быстрее, чем маллок + фри в 1,69 раза

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

Сам по себе этот тест ещё ничего не доказывает.

Запустил свой тест, померял производительность. Похоже, что действительно, скорость работы у них одна и та. Использовал gcc. Видимо, действительно, либо в справочнике какая-то путаница, либо gcc и clang игнорируют стандарт и используют в С99 подход их С98. В любом случае, дальнейшие разбирательства излишни. Либо тут какая-то ошибка, либо стандарт тупо дал послабление для убогих систем.

Всё же, на всякий случай, процитирую справочник.

Действие ф-ции realloc() в версии С99 немного отличается от того, что она делает в языках С++ и С89, хотя результаты совпадают... ...В версии С99 блок памяти, адресуемый параметром ptr освобождается, а вместо него выделяется новый блок. Содержимое блока совпадает с содержимым исходного (по крайней мере совпадают первые size байтов). Функция возвращает указатель на новый блок. Причём разрешается, чтобы новый и старый блоки начинались с одинакового адреса

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

malloc / realloc - это libc

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

malloc / realloc - это libc

и к компилятору не имеют никакого отношения.

anonymous
()

почему realloc() в С99 — сразу выделяет память на новом месте?

Почему Вы читаете сказочки, а не стандарт?

The realloc function returns a pointer to the new object (which may have the same value as a pointer to the old object), or a null pointer if the new object could not be allocated.

Текст выше - из C99. В C11 - то же самое.

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

1. Как связано «С99 — сразу выделяет память на новом месте» с «разрешается, чтобы новый и старый блоки начинались с одинакового адреса». «Места» в памяти как бы только адресом и различаются.

2. Есть такое изменение в стандарте, цитата из C99rationale:

A new feature of C99: the realloc function was changed to make it clear that the pointed-to object is deallocated, a new object is allocated, and the content of the new object is the same as that of the old object up to the lesser of the two sizes. C89 attempted to specify that the new object was the same object as the old object but might have a different address. This conflicts with other parts of the Standard that assume that the address of an object is constant during its lifetime.

И это правка неоднозначностей стандарта.

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

Почему Вы читаете сказочки, а не стандарт?

когда покажете документацию на С/С++, изданную в России в бумажном виде, тогда и поговорим

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

1. Вот как раз, видимо, и имеется в виду, что блок как бы «убивается», и выделяется новый, который может иметь тот же адресс, что и старый, а может - нет. Т.е. с точки зрения программы — это однозначно новый блок.

2. Ясно. Походу, дело совсем не в физическом изменении подхода, а уточнении философского понимания старого: по стандарту адресс объекта не изменен всю его (объекта) жизнь. В то же самое время, в С89 говорится что новый объект — это старый, но с новым адрессом, поскольку это - деление на ноль, в С99 просто уточнили формулировку, при этом фактическое поведение ф-ции не изменилось.

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

Походу, дело совсем не в физическом изменении подхода, а уточнении философского понимания старого

Вполне себе практическое уточнение, а не философское. Оно означает, что объект после realloc()'а в общем случае нужно переиницилизоровать. Т.е. если внтури объекта были абсолютные ссылки на самого себя, то их нужно пересчитать. Тоже самое касается размеров и ссылок на этот блок из внешних объектов. Технически нельзя просто скопировать контент объекта так, чтобы он остался валидным.

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

Патриотичненький такой подход к изучению языка, одобряю.

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