Как C / C ++ знает, как долго динамически распределенный массив - PullRequest
1 голос
/ 11 марта 2011

Этот вопрос уже давно беспокоит меня.

Если я, например, int* a = new int[n], у меня есть только указатель, указывающий на начало массива a, но как C / C ++ узнает о n?Я знаю, что если я хочу передать этот массив другой функции, то мне нужно передать длину массива вместе с ним, поэтому я предполагаю, что C / C ++ действительно не знает, как долго этот массив.

Я знаю, что мы можем вывести конец массива символов char*, ища терминатор NUL.Но есть ли подобный механизм для других массивов, например, int?Между тем, char может быть больше, чем символ - вы также можете рассматривать его как целочисленный тип.Тогда как C ++ узнает, где заканчивается этот массив?

Этот вопрос начинает беспокоить меня еще больше, когда я разрабатываю встроенный Python (если вы не знакомы со встроенным Python, вы можете проигнорировать этот абзац и просто ответить на вышеуказанные вопросы. Я все равно буду признателен).В Python существует «ByteArray», и единственный способ преобразовать этот «ByteArray» в C / C ++ - это использовать PyString_AsString () для преобразования его в char *.Но если этот ByteArray содержит 0, то C / C ++ считает, что массив char * останавливается раньше.Это не самая плохая часть.Хуже всего, скажем, что я делаю

char* arr = PyString_AsString(something)
void* pt = calloc(1, 1000); 

, если st начинается с 0, тогда C / C ++ почти гарантирует уничтожение всего в arr, так как думает, что arr заканчивается сразу после появления NULL,Тогда он может просто уничтожить все в arr, выделив ствол памяти для pt.

Большое спасибо за ваше время!Я очень ценю это.

Ответы [ 3 ]

7 голосов
/ 11 марта 2011

C / C ++ нет; это allocator (маленький кусочек кода, который реализует malloc(), free() и т. д.), который знает, как долго это будет. C / C ++ приветствуется во всем мире, без ограничений по поводу длины.

Также PyString_AsStringAndSize().

4 голосов
/ 11 марта 2011

Давайте ударим дизассемблер!Это будет отличаться для C и C ++.Как free работает в C, рассматривается в другом вопросе, и вот как это работает в C ++:

struct T {
    ~T();
    int data;
};
void test(T* p)
{
    delete[] p;
}

И давайте запустим компилятор для создания сборки.Вот соответствующие биты, скомпилированные для i386:

    movl    -4(%edi), %eax
    leal    (%edi,%eax,4), %esi
    cmpl    %esi, %edi
    je      L4
    .align 4,0x90
L8:
    subl    $4, %esi
    movl    %esi, (%esp)
    call    L__ZN1TD1Ev$stub
    cmpl    %esi, %edi
    jne     L8

. Вы можете увидеть важную часть: перед началом p хранится целое число, содержащее длину p, и код затем зацикливаетсянад массивом p, вызывая деструктор для каждого элемента в массиве.Затем он вызывает delete, что обычно довольно скучно, потому что он просто вызывает free (функция C).Таким образом, вы можете увидеть, как C ++ delete выражается в виде free.

Деструкторы и исключения: На основе вышеуказанной сборки вы можете заметить, что если деструктор для T выдает исключение, тогда часть массива p будет вызывать деструктор, а остальная часть массива - нет.Деструкторы никогда не должны выдавать исключения.

Предупреждение: Это только один из возможных способов, с помощью которого ваш компилятор и среда выполнения могут решить эту проблему.(Здесь деструктор вызывается сгенерированным компилятором кодом, и delete является частью среды выполнения.) Существует довольно много возможностей для их реализации, и ваш может отличаться.Это также показывает, почему вы всегда должны вызывать правильный оператор, delete[] или delete - вызов неправильного оператора вызовет всевозможные проблемы, такие как топание памяти и освобождение недействительных указателей.

О NUL-терминаторах: Единственная причина, по которой NUL-терминаторы являются проблемой, заключается в том, что PyString_AsString и другие подобные функции вызывают strlen, чтобы выяснить, какова длина строки.Однако free не заботится о NUL-терминаторах, вместо этого он отдельно отслеживает длину от исходного вызова malloc.Для PyString_AsStringstrdup и т. Д.) Это не вариант, потому что нет портативного способа получить размер области памяти - malloc и free не предоставляют эту функциональность.Кроме того, вы можете передать указатель на PyString_AsString, который находится в середине блока malloc или где-то еще целиком.

0 голосов
/ 11 марта 2011

c / c ++ не знает длины любого массива, поэтому вы можете легко получить доступ к массиву через границу.c / c ++ также не знает длину массива char.

Char * может указывать на строку, но она не равна строке.Строка, оканчивающаяся NULL, является соглашением c / c ++.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...