У меня есть следующий код ниже (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
Вообще 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 будет оцениваться каждый раз, когда он встречается в вашем коде.
Других решений пока нет …