Наличие этого кода:
typedef volatile int COUNT;
COUNT functionOne( COUNT *number );
int functionTwo( int *number );
Я не могу избавиться от некоторых предупреждений..
Я получаю это предупреждение 1 в functionOne прототипе
[Предупреждение] спецификаторов типа проигнорировано на функциональном типе возврата
и я получаю это предупреждение 2, везде, где я называю functionTwo с аргументом указателя КОЛИЧЕСТВА вместо международного указателя
[Предупреждение] броска отбрасывает спецификаторы от целевого типа указателя
очевидно, переменные/указатели не могут быть "брошены" к volatile/un-volatile.. но каждый аргументы должны быть указаны как энергозависимые также? таким образом, как я могу использовать какую-либо библиотечную функцию, если она уже определяется для энергонезависимой переменной?
Править: Использование gcc -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wextra -Wstrict-prototypes -Wmissing-prototypes …
Править: После совета Jukka Suomela это - пример кода для предупреждения два
typedef volatile int COUNT;
static int functionTwo(int *number) {
return *number + 1;
}
int main(void) {
COUNT count= 10;
count = functionTwo(&count);
return 0;
}
Ключевое слово volatile
было разработано для применения к объектам, представляющим собой хранилище, а не к функциям. Возвращать volatile int
из функции не имеет особого смысла. Возвращаемое значение функции не будет оптимизировано (за исключением встроенных функций, но это совсем другое дело...), и ни один внешний агент не будет его изменять. Когда функция возвращается, она передает копию возвращаемого значения вызывающей функции. Копия объекта volatile
сама не является volatile
. Поэтому попытка вернуть volatile int
приведет к копированию, отбрасывая его к энергонезависимому int
, что и вызывает сообщения компилятора. Возврат volatile int*
может быть полезен, но не volatile int
.
Передача объекта по значению в функцию делает копию объекта, поэтому использование volatile int
в качестве параметра функции обязательно включает преобразование, которое игнорирует классификатор. Передача volatile по адресу вполне разумна, но не по значению.
Согласно спецификации C, поведение volatile
полностью зависит от реализации, так что YMMV.
Вы используете volatile
таким образом, чтобы попытаться победить какую-то оптимизацию компилятора? Если да, то, вероятно, есть лучший способ сделать это.
Edit:
Принимая во внимание обновления к вашему вопросу, кажется, что вы можете подойти к этому по-другому. Если вы пытаетесь победить оптимизацию компилятора, почему бы не использовать прямой подход и просто сказать компилятору не оптимизировать некоторые вещи? Вы можете использовать #pragma GCC optimize
или __attribute__((optimize))
чтобы задать конкретные параметры оптимизации для функции. Например, __attribute__((optimize(0))))
отключает все оптимизации для данной функции. Таким образом, вы сможете сохранить типы данных энергонезависимыми и избежать проблем с типами, с которыми вы столкнулись. Если отключение всех оптимизаций - это слишком, вы также можете включить или выключить отдельные опции оптимизации с помощью этого атрибута/прагмы.
Edit: Я смог скомпилировать следующий код без каких-либо предупреждений или ошибок:
static int functionTwo(int *number) {
return *number + 1;
}
typedef union {
int i;
volatile int v;
} fancy_int;
int main(void) {
fancy_int count;
count.v = 10;
count.v = functionTwo(&count.i);
return 0;
}
Этот хак "техника", вероятно, имеет какие-то странные побочные эффекты, поэтому тщательно проверьте его перед производственным использованием. Скорее всего, он ничем не отличается от прямого приведения адреса к (int*)
, но не вызывает никаких предупреждений.
Вполне возможно, что я здесь не совсем так, но volatile не является чем-то, что обычно связано с областью памяти стека. Поэтому я не уверен, действительно ли следующий прототип имеет смысл.
volatile int functionOne(volatile int number);
Я не уверен, как возвращаемое целое число может быть изменчивым. Что приведет к изменению стоимости EAX? То же самое и с целым числом. Когда значение помещается в стек, чтобы его можно было передать в качестве параметра, что изменит его значение?
Если я компилирую
typedef volatile int COUNT;
static int functionTwo(int number) {
return number + 1;
}
int main(void) {
COUNT count = 10;
count = functionTwo(count);
return 0;
}
используя
gcc -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith -Wcast-qual \
-Wextra -Wstrict-prototypes -Wmissing-prototypes foo.c
я не получаю никаких предупреждений. Я пробовал gcc 4.0, 4.2, 4.3 и 4.4. Ваше warningTwo звучит так, как будто вы передаете указатели, а не значения, а это уже другая история...
EDIT:
Ваш последний пример должен быть написан так; опять же, никаких предупреждений:
typedef volatile int COUNT;
static int functionTwo(COUNT *number) { return *number + 1; }
int main(void) { COUNT count = 10; count = functionTwo(&count); return 0; }
EDIT:
Если вы не можете изменить functionTwo:
typedef volatile int COUNT;
static int functionTwo(int *number) { return *number + 1; }
int main(void) {
COUNT count= 10;
int countcopy = count;
count = functionTwo(&countcopy);
return 0;
}
Обратите внимание, что любой доступ к переменной volatile является "специальным". В первой версии с functionTwo(COUNT *number)
, functionTwo знает, как правильно обращаться к ней. Во второй версии с countcopy главная функция знает, как правильно обращаться к ней при присвоении countcopy = copy.
Я не понимаю, зачем вам нужен квалификатор volatile
для возвращаемого типа функции. Вместо этого переменная, которой вы назначаете возвращаемое значение функции, должна быть набрана как volatile
.
Попробуйте внести следующие изменения:
typedef int COUNT_TYPE;
typedef volatile COUNT_TYPE COUNT;
COUNT_TYPE functionOne( COUNT number );
COUNT_TYPE functionTwo( COUNT_TYPE number );
И при вызове functionTwo ()
явно укажите аргумент:
functionTwo( (COUNT_TYPE)arg );
HTH, Ашиш.
Возможно, те, кто это писал, хотели быть уверены, что все операции атомарны, и объявили все переменные int как volatile (это MT-приложение с плохой синхронизацией?), поэтому все ints из кода объявлены как volatile "для согласованности".
А может быть, объявив тип функции как volatile, они рассчитывают прекратить оптимизацию повторных вызовов чистых функций? Приращение статической переменной внутри функции решило бы эту проблему. Однако попробуйте угадать их первоначальный замысел, потому что это просто не имеет никакого смысла.