#c #assembly #stack #rvalue
Вопрос:
Первый вопрос здесь. Через несколько недель/месяцев мне нужно будет создать процедурный код, в котором будут функции, назначающие большие (я имею в виду действительно большие) наборы данных непосредственно указателям. Вот пример кода, который я буду выполнять :
void MyFuntion(string* str)
{
*str = "some data in a string";
}
Как это, безусловно, важно : я нахожусь в Windows 10, в visual-studio 2019, компилируюсь с компилятором c по умолчанию в выпуске x86.
Представьте себе что-то подобное, но со строками, которые могут содержать несколько миллионов символов, или с массивами int/float, также содержащими несколько миллионов элементов. Таким образом, это единственная операция, присваивающая значение r указателю, который, следовательно, находится в куче. Конечно, если я создам локальную переменную, содержащую данные, она будет больше 1 МБ и, следовательно, вызовет переполнение стека, верно ?
Как я понимаю, поскольку данные здесь существуют только как значение r, у них нет памяти, но я хотел бы знать : как значение r присваивается указателю ? Например, как это делается в сборке ? Я должен сказать, что я никогда не занимался сборкой, у меня есть несколько (очень мало) идей, но я хотел бы заняться этим, когда у меня будет время.
Является ли он временным, созданным в стеке или куче перед помещением в конечный адрес памяти ? Я предполагаю, что адрес памяти (указатель, в котором я назначаю данные) непосредственно заполняется данными, например, по частям, поэтому значения rvalue в памяти не существует.
Если я прав, единственными вещами, которые существуют в стеке здесь, являются : вызов функции, копирование указателя, затем инструкция, которая должна быть чем-то вроде «присвоить значение X значению Y», и размер инструкции не зависит от размера значения r и значения l, поэтому здесь не должно быть никаких проблем со стеком.
Итак, если я прав, этот код не должен вызывать никаких проблем, независимо от того, насколько велико значение r, но я все равно хотел бы знать, как это делается точно, с точки зрения сборки. Обратите внимание, что я не только ищу ответ, но и больше похож на некоторые ссылки, книги или документы, которые могли бы подробно объяснить. Я предполагаю, что то, что я ищу, не будет в книге на c , но больше похоже на книгу по сборке, это может быть хорошей отправной точкой для того, чтобы погрузиться в нее !
Комментарии:
1. Если
string
std::string
да , то это не просто присвоение переменной, а вызов оператора присвоения строки. В сборке это выглядит иначе, чем присвоение примитивного типа.2. @PeterCordes Да, но я не уверен, что эти детали (особенно возможная оптимизация) — это то, о чем на самом деле спрашивают. Когда я читаю вопрос, они предполагают, что в
foo = huge_immediate_data;
данных нигде не было данных до инструкции, и предполагают, что они будут переведены в большое количествоmov
инструкций с непосредственными значениями. Я пытался указать, что существует такая вещь, как статическое хранилище.3. @olm: да, прочитав больше вопросов, согласился. Я точно знаю, какие неправильные представления есть у спрашивающего, но они включают идею о том, что сама инструкция может быть в стеке. (Этого не может быть.) Так что да, цикл, который копирует из статического хранилища, является ключевым моментом для того, что будет делать конструктор при передаче
char*
значения r в абстрактной машине C . Оптимизация с этого момента зависит от компилятора, но да, нет никаких причин для какого-либо использования стека вообще, за исключением обратного адреса. Пара скалярных вещей, таких как указатель, могут поместиться в регистрах.4. Да, «статический класс хранения» языка Си-это место, где живут символы строковых литералов, а также глобальные и
static
переменные. Они обычно реализуются с помощью статического хранилища на языке ассемблера, которое да включает.data
,.bss
,.rodata
(где вы найдете строковые литералы и другие константы) и.text
раздел, в котором вы найдете машинный код. (Помните, что C и C предназначены для компиляции с опережением времени, нет необходимости в создании кода во время выполнения в куче или стеке. В стеке asm в обычной реализации хранятся только указатели функций и такие вещи, как адреса возврата).5. только записывает значение rvalue непосредственно по адресу, указанному str — нет, в C он запускает
std::string::operator=(const char*)
функцию дляstd::string
объекта с указаниемdelete
на старую строку и создает новую из строки с указанием на C. Значение rvalue, указывающее на строковый литерал, становится функцией arg. Если бы вы выбрали пример с примитивным типом , напримерconst char **str
, тогда да , вы бы просто сохраняли указатель (на статическое хранилище) в объект указателя размером 4 или 8 байт, на который указываетstr
, где бы это ни было (стек, «куча»,. data или .bss).