У меня есть много кода, который был похож на это:
int num = 15;
if(callback)
callback(&num); /* this function may or may not change the value of num */
if(num == 15) /* I assumed num did not need to be volatile and is reloaded */
do_something();
else
do_something_else();
Однако теперь у меня есть более сложные структуры и указатели на них:
struct example { int x,y,z; };
struct example eg, eg2, *peg;
int whatever;
char fun;
struct variables { struct example **ppeg; int *whatever; char *fun; };
struct variables myvars;
peg = ⪚
myvars.ppeg = &peg;
myvars.whatever = &whatever;
myvars.fun = &fun;
[...]
peg->x = 15;
if(callback)
callback(&myvars); /* this function may or may not change the variables */
if(peg->x == 15) /* Can I assume that x is "reloaded" ? */
do_something();
else
do_something_else();
Верьте или нет, это все еще слишком упрощено. Теперь, очевидно, я мог бы использовать volatile, я полагаю, я мог бы сделать что-то вроде этого, чтобы вызвать перезагрузку:
if(*(volatile int *)&peg->x == 15)
Это гарантирует перезагрузку? Другими словами, смогу ли я потом написать просто, если (peg-> x), зная, что один изменчивый бросок уже «перезагрузил» переменную?
Проблема в скорости, так как мою функцию можно вызывать постоянно, миллионы раз. Это, конечно, намного сложнее, чем выше. Интересно, было бы необходимо или предпочтительно иметь сигнал обратного вызова, если он изменяет переменные, и есть ли какой-то способ справиться с этим. Я имею дело с десятками переменных в структуре, и я не хочу, чтобы они перезагружались без необходимости.
Кроме того, стандарт C99 имеет представление о любом из моих двух псевдосэмплов, например, чтобы гарантировать, что после функции переменные «перезагрузятся» (я не знаю правильного слова). Или это проблема компилятора и уровня оптимизации? Я проверил некоторые другие подобные разбавленные образцы с gcc при -O0 и -O3, и я не увидел разницы ни в одном случае (во всех случаях переменные имели свое правильное значение).
Спасибо всем!
РЕДАКТИРОВАНИЕ 24/24/2010 13:00 EST: чтобы ответить на комментарии о том, что я имею в виду под "перезагрузкой", я имел в виду, что компилятор кэширует переменную (например, в регистре или другом пространстве памяти) до того, как вызов функции все еще получит та же самая кэшированная переменная после вызова функции, а не (возможно) обновленная переменная.
Также компиляторы могут поднять цикл, чтобы удалить переменные из цикла, которые не меняются. Например, если у меня есть peg-> x, а не доступ к peg-> x каждый раз в цикле, может ли компилятор определить, что других обращений нет, даже если обратный вызов передан & peg? Если у меня есть такой код:
peg = ⪚
while(1)
{
if(!peg->x)
if(callback)
callback(peg);
if(!peg->x)
peg->x = 20;
if(peg == &eg)
peg = &eg2;
else
break;
}
Так может ли компилятор оптимизировать его, например, так:
while(1)
{
if(!peg->x)
{
if(callback)
callback(peg);
peg->x = 20;
}
if(peg == &eg)
peg = &eg2;
else
break;
}
или это можно оптимизировать так:
{
int someregister;
peg = ⪚
someregister = peg->x;
if(!someregister)
if(callback)
callback(peg);
if(!someregister)
peg->x = 20;
peg = &eg2;
someregister = peg->x;
if(!someregister)
if(callback)
callback(peg);
if(!someregister)
peg->x = 20;
}
РЕДАКТИРОВАТЬ 24.11.2010 13:45 EST: вот еще один пример. Обратный вызов может изменить указатель на себя.
if(psomestruct->callback)
{
psomestruct->callback(psomestruct); /* this callback could change the pointer to itself */
if(psomestruct->callback) /* will the compiler optimize this statement out? */
psomestruct->callback(psomestruct);
}