Изменчивые переменные как аргумент функции

Наличие этого кода:

typedef volatile int COUNT;       

COUNT functionOne( COUNT *number );

int  functionTwo( int *number );

Я не могу избавиться от некоторых предупреждений.

Я получаю это предупреждение 1 на прототипе functionOne

[Предупреждение] возвращаемый тип функции

и я получаю это предупреждение 2, где я вызываю functionTwo с аргументом COUNT указатель вместо указателя int

[Предупреждение] листы отбрасывают квалификаторы из целевого типа указателя

очевидно, что переменные/указатели не могут быть "приведены" во volatile/un-volatile. но все аргументы должны быть указаны как изменчивые тоже? так как я могу использовать любую библиотечную функцию, если она уже определена для нелетучей переменной?

EDIT: с помощью 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;
}

Ответ 1

Ключевое слово volatile предназначено для применения к объектам, которые представляют собой хранилище, а не к функциям. Возврат a volatile int из функции не имеет большого смысла. Возвращаемое значение функции не будет оптимизировано (возможно, за исключением встроенных функций, но это другой случай вообще...), и никакой внешний актер не будет изменять его. Когда функция возвращается, она передает копию возвращаемого значения вызывающей функции. Копия объекта volatile сама не является volatile. Таким образом, попытка вернуть volatile int приведет к копированию, отбрасывая его до энергонезависимого int, что является тем, что запускает ваши сообщения компилятора. Возвращение volatile int* может быть полезно, но не volatile int.

Передача объекта по значению в функцию делает копию объекта, поэтому использование volatile int в качестве параметра функции обязательно включает преобразование, которое игнорирует квалификатор. Передача изменчивого по адресу вполне разумно, но не по значению.

В соответствии с спецификацией 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;
}

Этот метод hack, вероятно, имеет какие-то странные побочные эффекты, поэтому тщательно проверяйте его перед использованием. Скорее всего, это не так, что прямое обращение адреса к (int*), но оно не вызывает никаких предупреждений.

Ответ 2

Возможно, что я ухожу от базы, но volatile - это не что-то, что обычно связано с областью памяти стека. Поэтому я не уверен, действительно ли имеет смысл следующий прототип.

volatile int functionOne(volatile int number);

Я не уверен, как возвращаемое целое число может быть изменчивым. Что изменит ценность EAX? То же самое относится к целому. Как только значение вставляется в стек так, что его можно передать как параметр, который изменит его значение?

Ответ 3

Если я компилирую

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. Ваше предупреждение. Два звучат так, будто вы передаете указатели, а не значения, и это еще одна история...

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:

Если вы не можете изменить функциюTwo:

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;
}

Обратите внимание, что любой доступ к изменчивой переменной является "специальным". В первой версии с functionTwo(COUNT *number) functionTwo знает, как обращаться к ней должным образом. Во второй версии с countcopy основная функция знает, как правильно ее получить при назначении countcopy = copy.

Ответ 4

Я не понимаю, почему вы хотите иметь квалификатор 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 );

НТН, Ashish.

Ответ 5

Возможно, что те, кто его написал, хотели убедиться, что все операции являются атомарными и объявили все переменные int волатильными (это приложение MT с плохой синхронизацией?), поэтому все int из кода объявляются как летучих "для согласованности".

Или, может быть, объявив тип функции как изменчивый, они ожидают прекратить оптимизацию повторных вызовов для чистых функций? Приращение статической переменной внутри функции могло бы решить ее. Однако попытайтесь угадать их первоначальное намерение, потому что это просто не имеет никакого смысла.