Звонок по имени (нормальная оценка заказа)

У меня есть следующий код ниже (C, как язык). Я знаю, как отследить, использовалась ли передача по значению или передача по ссылке, но есть также механизм вызова по имени. Кто-нибудь может подсказать мне, как отследить звонок по имени?

int x=12,y=10;
void tswap(int pa, int pb) {
int tmp;
tmp=pa;
pa=pb;
pb=tmp;
x=x+pa;
x=x-pb;
y++;
printf("%d %d %d %d\n",pa,pb,x,y);
}
int main() {
int a=4;
tswap(x,a);
printf("%d %d %d\n",x,y,a);
tswap(++x,++y);
printf("%d %d %d\n",x,y,a);
return 0;
}

Если будет использоваться передача по значению, то результат будет выглядеть следующим образом:

4 12 4 11

4 11 4

12 5 12 13

12 13 4

0

Решение

Вообще C ++ делает не использовать по имени. Вызов по имени означает, что аргумент функции не оценивается при вызове функции. Он ведет себя так, как будто аргумент будет подставлен в тело функции.

Пример:

void foo(int a, int b) {
int s = 0;
for(int i=0; i<n; i++) {
s += b;
}
}

Обычно в C ++ пример выражения x = foo(3,bar(7)); будет вести себя примерно так:

int tmp = bar(7);
x = foo(3,tmp);

bar оценивается один раз и результат передается функции foo,

Язык, который будет использовать вызов по имени, потенциально может трансформироваться foo(3,bar(7)); в

void foo() {
int s = 0;
for(int i=0; i<3; i++) {
s += bar(7);
}
}

В первом случае функция bar будет оцениваться один раз, во втором случае будет оцениваться 3 раз.


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

Пример:

inline unsigned foo(unsigned a, unsigned b) {
return a / b;
}

Если вы позвоните a = foo(x,2); компилятор будет достаточно умен, чтобы перевести это на a = x/2; а затем a = x >> 1;,

Это даже доходит до этого примера:

inline int foo(int a, int b) {
if(a == 0) return 0;
else return b;
}

Теперь компилятор действительно может преобразовать x = foo(0,bar(17)); в x = 0; таким образом, никогда не вызывая функцию bar, Я думаю, что эта оптимизация выполняется только тогда, когда bar не имеет побочных эффектов.


Хотя C ++ не использует вызов по имени, вы можете легко использовать его в C ++. Просто дайте функциональный объект / указатель на вашу функцию.

Пример:

template<typename F>
int foo(int a, F b) {
int s = 0;
for(int i=0; i<a; i++) {
s += b();
}
}

Теперь с foo(3, []() { static int i=0; return i++; })где второй аргумент является лямбда-кодом C ++ 11, b будет оцениваться каждый раз, когда он встречается в вашем коде.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]