изменчивые переменные как аргумент функции - PullRequest
8 голосов
/ 22 июля 2010

Имея этот код:

typedef volatile int COUNT;       

COUNT functionOne( COUNT *number );

int  functionTwo( int *number );

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

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

Спецификаторы типа [Warning] игнорируются при возвращении функции типа

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

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

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

РЕДАКТИРОВАТЬ : Использование 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;
}

Ответы [ 5 ]

8 голосов
/ 22 июля 2010

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

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

Согласно спецификации C поведение volatile полностью зависит от реализации, поэтому YMMV.

Используете ли выvolatile таким образом попытаться победить какую-то оптимизацию компилятора?Если это так, то, вероятно, есть лучший способ сделать это.

Редактировать: Принимая во внимание обновления вашего вопроса, кажется, что вы можете подойти к этому по-другому,Если вы пытаетесь победить оптимизацию компилятора, почему бы не воспользоваться прямым подходом и просто сказать компилятору не оптимизировать некоторые вещи?Вы можете использовать #pragma GCC optimize или __attribute__((optimize)), чтобы задать конкретные параметры оптимизации для функции.Например, __attribute__((optimize(0))) должен отключить все оптимизации для данной функции.Таким образом, вы можете сохранить свои типы данных энергонезависимыми и избежать проблем с типами, которые у вас возникают.Если отключить все оптимизации слишком много, вы также можете включить или отключить отдельные параметры оптимизации с помощью этого атрибута / прагмы.

Редактировать: Мне удалось скомпилировать следующий код без каких-либопредупреждения или ошибки:

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*), но он не вызывает никаких предупреждений.

3 голосов
/ 22 июля 2010

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

volatile int functionOne(volatile int number);

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

2 голосов
/ 22 июля 2010

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

2 голосов
/ 22 июля 2010

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

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:

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

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) функция два знает, как правильно обращаться к ней. Во второй версии с countcopy основная функция знает, как правильно обращаться к ней при назначении countcopy = copy.

0 голосов
/ 22 июля 2010

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

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

...