У меня есть группа функций, которые объявлены как static
и fastcall
. Большинство из них используют указатель на структуру, которая более или менее выполняет роль this
в C++. Некоторым функциям ничего не нужно в структуре, но ради единообразия я все равно хочу передать им указатель. Заметит ли компилятор, что аргумент не используется, и пропустит выделение для него регистра?
Будет ли компилятор оптимизировать неиспользуемые аргументы статической функции?
Ответы (3)
Я написал эту бессмысленную программу, чтобы проверить это. В функции есть какой-то бессмысленный код, и она вызывает ее несколько раз, потому что в противном случае компилятор просто встраивает весь вызов функции, что делает тест бесполезным. (Я знаю, это странная смесь C и C++.... глупый код, но все еще работает, чтобы продемонстрировать проблему)
#include <stdio.h>
#include <vector>
#include <algorithm>
using namespace std;
struct demo
{
int a;
char ch;
};
static void __fastcall func(struct demo* d)
{
for(int i = 0; i < 100; i++) {
std::vector<int> a;
std::sort(begin(a), end(a));
printf("THis is a test");
printf("Hello world\n");
}
}
int main()
{
// void*p = (void*)&func;
struct demo d;
func(&d);
func(&d);
func(&d);
func(&d);
func(&d);
func(&d);
func(&d);
//printf((const char*)p);
}
Как написано там, функция вызывает компиляцию для этого: -
func(&d);
00F61096 call func (0F61000h)
func(&d);
00F6109B call func (0F61000h)
func(&d);
00F610A0 call func (0F61000h)
func(&d);
00F610A5 call func (0F61000h)
func(&d);
00F610AA call func (0F61000h)
func(&d);
00F610AF call func (0F61000h)
func(&d);
00F610B4 call func (0F61000h)
Что показывает, что компилятор действительно пропустит параметр, если он не используется. Однако если я раскомментирую две строки, чтобы взять адрес функции, тогда все изменится, вместо этого будет сгенерировано это: -
00C71099 lea ecx,[esp]
00C7109C call func (0C71000h)
func(&d);
00C710A1 lea ecx,[esp]
00C710A4 call func (0C71000h)
func(&d);
00C710A9 lea ecx,[esp]
00C710AC call func (0C71000h)
func(&d);
00C710B1 lea ecx,[esp]
00C710B4 call func (0C71000h)
Куда он ДЕЙСТВИТЕЛЬНО отправляет указатель.
Я предполагаю, что в первом случае компилятор может доказать, что если он сгенерировал пользовательское соглашение о вызовах функции, то не может быть каких-либо видимых пользователем эффектов, но во втором случае, когда вы берете указатель на функцию, функция может быть вызван из другого отдельно скомпилированного модуля, у которого нет возможности узнать, нужен этот параметр или нет. Хотя в этом случае не имеет значения, был ли установлен регистр или нет, в общем случае компилятор должен придерживаться точного шаблона вызова, поэтому я предполагаю, что он сгенерировал наиболее общий код и не будет использовать пользовательские соглашения о вызовах, если это возможно. не доказывает, что он может видеть весь код, который может вызвать функцию.
В любом случае, чтобы ответить на вопрос, нет, компилятор не всегда будет передавать неиспользуемые параметры в регистр, но я, конечно, не стал бы писать какой-либо код, который зависит от какого-либо конкретного поведения здесь, поскольку изменение несвязанного кода в другом месте (взяв адрес функции), измененный такое поведение и нет ничего гарантированного ни одним стандартом, который я вижу.
Прежде всего, компилятор должен предупредить вас о неиспользуемых аргументах функции, если вы используете правильные флаги компилятора (например, -Wall). Я бы рекомендовал оставить аргументы, которые вы не используете, вне списка аргументов, хотя я думаю, они будут оптимизированы. Что вы можете сделать, чтобы убедиться, однако, скомпилируйте свой код дважды, один раз с аргументами и один раз без, и выполните diff
между двоичными файлами и посмотрите, совпадают ли они. Я думаю, это должно зависеть от используемого вами компилятора и флагов оптимизации.
Ваше здоровье,
Энди
diff
- нельзя будет проверить различия (поскольку выполнение зависит от многих других вещей, которые могут различаться для каждого процесса выполнения, кроме того, инициализация переменной не займет много времени
- person exexzian; 12.01.2013
do a diff between the binaries
- я спрашиваю diff b/w двоичные файлы чего? время выполнения или ??
- person exexzian; 12.01.2013
Вы можете опустить аргумент в определении функции. Это даст компилятору подсказку, что конкретный аргумент не используется, он воспользуется этим и оптимизирует код.
void func(struct demo *) { ... }