Переносимая функция на C (без ассемблера), которая возвращает размер фрейма стека

Напишите переносимую функцию на C (без ассемблера), которая возвращает размер фрейма стека.

int stackframe_size()
{

}

Попытка решить ее, как показано ниже. Эта функция возвращает 228 байт при компиляции с VS 2010. Есть ли способ проверить ее правильность?

    int stackframe_size(int run)
    {
        int i ;

        if(!run)
        {
            return ((int)(&i) - stackframe_size(++run));

        }
        return (int)(&i);

    }

Вызывается как:

    int main()
    {
        printf("\nSize of stackframe_size() is: %d bytes",stackframe_size(0)) ;
        return 0;
    }

person Electrix    schedule 06.02.2015    source источник
comment
:) Я спросил об этом, так как хотел проверить, есть ли умный/более чистый способ сделать это без добавления локальных переменных, которые считывают адреса аргументов (например, с использованием техники рекурсии).   -  person Electrix    schedule 06.02.2015
comment
По мне так хорошая техника. Возможно, вам следует поделиться этим кодом и объяснить, как он работает и какие результаты вы получаете.   -  person user3386109    schedule 06.02.2015
comment
У вас не может быть такой функции portable. Гипотетический компилятор, оптимизирующий всю программу, может иногда генерировать код без стека; и можно представить какой-нибудь компилятор C без стеков (но размещающий все фреймы вызовов в какой-то куче мусора, как это делал SML/NJ). Так что в принципе стек даже не требуется. Но я не знаю таких странных реализаций C без стеков!   -  person Basile Starynkevitch    schedule 06.02.2015
comment
Кроме того, компиляторам разрешено оптимизировать рекурсивную функцию (например, используя хвостовые вызовы).   -  person Basile Starynkevitch    schedule 06.02.2015
comment
@BasileStarynkevitch - здесь нет хвостового звонка?   -  person Carl Norum    schedule 06.02.2015
comment
@Basile Starynkevitch Пример странной реализации: я использую компилятор для встроенного кода, который не допускает рекурсии - таким образом, он не соответствует C. Код с помощью статического анализа во время компиляции знает и назначает адрес каждой локальной переменной. Единственный стек — это адрес возврата, который, согласно тому же анализу, не превышает определенного уровня.   -  person chux - Reinstate Monica    schedule 06.02.2015
comment
Да, я думал о такой реализации (я говорил об оптимизации всей программы). Кстати, какая реализация?   -  person Basile Starynkevitch    schedule 06.02.2015
comment
Единственная другая вещь, на которую я укажу - которая, я думаю, еще не упоминалась, - это то, что ваша процедура (операция вычитания) предполагает, что второй вызов stackframe_size() будет иметь свой кадр стека, расположенный в физически более низком адресе памяти . Хотя это обычно (или даже обычно) верно, это не обязательно. Как уже говорили другие, сделать это портативным (даже если вы сделали сравнение abb перед вычитанием) - по сути, дурацкая затея.   -  person Dan    schedule 08.02.2015


Ответы (2)


Такая функция portable невозможна.

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

За исключением того, что ваш код вычитает до int значений, которые являются результатом конверсий из адресов. Скорее всего, будет работать прямое вычитание указателей, и указатели должны быть типа char* или unsigned char*. Есть много реализаций, в которых int слишком мал для хранения преобразованного указателя, а в некоторых указатели имеют более сложное представление, чем вы предполагаете, и преобразование их даже в достаточно большой целочисленный тип не обязательно даст вам осмысленный результат.

Существуют реальные реализации C, которые не используют «стек» в смысле непрерывной области памяти, в которую помещаются и извлекаются «кадры стека». (Должен существовать «стек» в смысле структуры данных «первым поступил — последним обслужен», но способ реализации этого «стека» совершенно не определен.) Некоторые реализации мэйнфреймов IBM, например, выделяют память для функции. call через что-то вроде кучи, чтобы не было определенной связи между адресами локальных переменных для двух таких вызовов.

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

person Keith Thompson    schedule 06.02.2015
comment
Престижность за то, что такая переносимая функция невозможна - реализации C даже не требуются для наличия стека. - person paxdiablo; 16.04.2015

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

Вы можете использовать &run вместо &i - это сэкономит вам локальную переменную.

Есть ли способ проверить его правильность?

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

person Carl Norum    schedule 06.02.2015