энергозависимые переменные как аргумент функции

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

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;
}
8
задан Jonathan Leffler 16 August 2016 в 17:54
поделиться

5 ответов

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

9
ответ дан 5 December 2019 в 10:38
поделиться

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

volatile int functionOne(volatile int number);

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

3
ответ дан 5 December 2019 в 10:38
поделиться

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

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.

2
ответ дан 5 December 2019 в 10:38
поделиться

Я не понимаю, зачем вам нужен квалификатор 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
ответ дан 5 December 2019 в 10:38
поделиться

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

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

0
ответ дан 5 December 2019 в 10:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: