LINUX.ORG.RU

А по-моему, вполне понятно почему он ругается: volatile переменные могут поменяться в любой момент и возможно именно об этом и речь.

А если сделать так:
volatile int i, j;

int I = i, J=j; // Тут мы заморозим значения...
if(I == J){ ... }

Все вышенаписанное - IMHO (Истинное Мнение Хрен Оспоришь)

anonymous
()
Ответ на: комментарий от anonymous

> volatile переменные могут поменяться в любой момент...

И что? Как это утверждение связано с порядком выполнения операндов?

Die-Hard ★★★★★
() автор топика
Ответ на: комментарий от sS

> Убрать -Wall

Понимаю.

Еще можно не использовать icc, выключить компьютер, уехать в Африку. И, наконец, самый радикальный способ -- застрелиться...

Die-Hard ★★★★★
() автор топика
Ответ на: комментарий от Die-Hard

> И что? Как это утверждение связано с порядком выполнения операндов?

Наверно то, что если они не volatile, то неопределенный порядок ни на что не влияет -- значит нет нужды в remark'е. Если они volatile то разный порядок может дать разные результаты -- значит стоит сделать remark.

dilmah ★★★★★
()
Ответ на: комментарий от Die-Hard

Вообще ты спросил как это можно убрать, тебе ответили. А ты дерзишь. Нехорошо. gcc кстати такой лажи не выдает. Так что поливать дерьмом лучше компилятор, а не программу

Chumka ★★★
()
Ответ на: комментарий от dilmah

dilmah (13.02.2005 20:49:16):

> ...если они не volatile, то неопределенный порядок ни на что не влияет... Если они volatile то разный порядок может дать разные результаты...

Что-то я туплю...

КАК порядок выполнения опреандов в сравнении может повлиять на результат? Это ж не функции! И как это связано с атрибутом volatile?

Но самое главное -- как от варнинга избавиться? Кто прагму знает?

Die-Hard ★★★★★
() автор топика
Ответ на: комментарий от Chumka

Chumka (13.02.2005 21:01:31):

> Вообще ты спросил как это можно убрать, тебе ответили.

Чем мои собственные варианты ответов (не пользоваться icc, не включать компьютер, застрелиться) хуже предложенного? Наверное, если я спрашиваю явно, как мне избежать варнинга при _установленной_ опции -Wall, то я спрашиваю именно то, что спрашиваю?

> Нехорошо.

А хорошо отвечать, если не знаешь, что ответить?

> Так что поливать дерьмом лучше компилятор, а не программу

Дерьмом лучше вообще не поливать ;)

Die-Hard ★★★★★
() автор топика
Ответ на: комментарий от Die-Hard

>КАК порядок выполнения опреандов в сравнении может повлиять на
>результат? Это ж не функции! И как это связано с атрибутом volatile

volatile указывает на то, что обновление и чтение переменных должно осуществляться до пересечения определенных точек (вроде это называется sequence points, хотя я плохо помню этот момент). В твоем случае прочитать переменные можно в разном порядке и может действительно быть разный результат. Хотя, вообще, глупо об этом предупреждать. Вроде как указание volatile уже должно говорить о том, что человек должен понимать, какие при этом возникают эффекты.

Murr ★★
()
Ответ на: комментарий от Die-Hard

> КАК порядок выполнения опреандов в сравнении может повлиять на результат? Это ж не функции! И как это связано с атрибутом volatile?

ну i и j volatile. это значит что они могут быть чем угодно, например они могут при чтении давать количество тактов процессора.

В этом случае например (i < j) может давать разный результат в зависимости от порядка вычисления i и j. Хороший компилятор считает нужным предупредить тебя об этом.

По моему icc выдает remarks и warnings. Может бороться только с warnings а на remarks плюнуть?..

dilmah ★★★★★
()
Ответ на: комментарий от Die-Hard

icc имеет 3 уровня сообщений

 1 - errors            (-w0) (1)
 2 - warnings       (-w1) (1+2)
 3 - remarks        (-w2) (1+2+3)

У тебя это remarks, то есть с -w1 их не будет ...

sS ★★★★★
()
Ответ на: комментарий от Die-Hard

>КАК порядок выполнения опреандов в сравнении может повлиять на результат? Это ж не функции! И как это связано с атрибутом volatile?

Ну, мало ли что. Может код, который может их параллельно модифицировать читает одну переменную, вычисляет, результат пишет в другую. Тогда порядок доставания их в регистры будет влиять.

А точно обе переменные должны быть volatile? Как остальной код выглядит?

smartly ★★★
()
Ответ на: комментарий от sS

Если ты хошь убрать конкретный тип ремарки - используй -wd(#ремарки)

В твоём случае это:

-Wall -wd981

sS ★★★★★
()
Ответ на: комментарий от sS

2sS:

> -Wall -wd981

Thanks.

Я так и делаю. Но мне хочется сохранить ремарку 981: у меня довольно запутанные параллельные потоки, и предупреждения о возможных сайд-эффектах мне очень даже нужны. В этом и проблема: в ворохе "запланированных" ремарок легко не заметить действительно актуальную.

Помнится, для таких случаев имелись подходящие прагмы...

Die-Hard ★★★★★
() автор топика
Ответ на: комментарий от Murr

2Murr:

Да, действительно -- нагуглил; оказывается, есть некий "стандарт" на sequence points, где доступ к volatile переменным рассматривается как потенциальный side-effect. Глупость, конечно. Имеется в виду нечто типа

volatile int i = 0;

... код, не меняющий i ...

if(i!=0) ...

Поскольку i -- volatile, то считается, доступ к ней в if'е считается потенциальным сайд-эффектом.

Как будто я не могу добиться того же без volatile...

Die-Hard ★★★★★
() автор топика
Ответ на: комментарий от Die-Hard

>Я так и делаю. Но мне хочется сохранить ремарку 981: у меня довольно запутанные параллельные потоки, и предупреждения о возможных сайд-эффектах мне очень даже нужны. В этом и проблема: в ворохе "запланированных" ремарок легко не заметить действительно актуальную.

>Помнится, для таких случаев имелись подходящие прагмы...

Как и раньше:

#pragma warning(disable:981)

Только какой смысл это делать руками в коде ?

sS ★★★★★
()
Ответ на: комментарий от sS

2sS :

Thanks,

То, что нужно.

> Только какой смысл это делать руками в коде ?

У меня всего пара десятков таких мест. Я их оберну типа
#ifdef __INTEL_COMPILER
#pragma warning(push)
#pragma warning(disable:981)
#endif
...
#ifdef __INTEL_COMPILER
#pragma warning(pop)
#endif
и мне полегчает :-)

Кстати, как бы это не столь неуклюже сделать?
Какой-нибудь макрос придумать...



Die-Hard ★★★★★
() автор топика
Ответ на: комментарий от Die-Hard

j может измениться в результате чтения i (и наоборот) - а вернее, они могут давать разный результат при чтении в разном порядке, - если i и j на самом деле ссылаются на какие-нибудь устройства ввода-вывода, volatile вроде и для этого предназначен. Я понимаю что в данном случае это автоматические переменные, но как говорится мало ли что :) Так что правильно icc ругается, это никогда не помешает. Особенно если ругань можно элементарно обойти, зафиксировав переменные перед сравнением.

Сорри что несколько криво выражаюсь, но думаю понятно.

Teak ★★★★★
()
Ответ на: комментарий от Teak

Teak (13.02.2005 23:39:08):

> j может измениться в результате чтения i ... если i и j на самом деле ссылаются на какие-нибудь устройства ввода-вывода,

Не понял.

Как может измениться одна целая переменная от того, что я _прочитал_ другую? Пусть они хоть куда ссылаются.

Die-Hard ★★★★★
() автор топика
Ответ на: комментарий от Die-Hard

> Как может измениться одна целая переменная от того, что я _прочитал_ другую? Пусть они хоть куда ссылаются.

контр-вопрос: приведи пожалуйста определение volatile. Может и вопросы пропадут..

dilmah ★★★★★
()
Ответ на: комментарий от Die-Hard

Сугубо теоретически. Потому это и remark, а не warnign :)

Пусть у нас i и j - два порта ввода-вывода некоего последовательного устройства. И к примеру читая i, мы собственно считываем данные из этого устройства, а читая j - получаем количество прочитанных байт. Чем не применение для модификатора volatile.

Понятно что автоматические переменные не бывают портами устройств ввода-вывода :) Но компилятор не обязан учитывать всё, если можно просто на всякий случай ругнуться, для надёжности. Чтение - это тоже действие, и при некоторых обстоятельствах в результате этого действия что-нибудь может измениться.

Teak ★★★★★
()
Ответ на: комментарий от Teak

2Teak (14.02.2005 0:38:53):

Это не Це, что ты описАл.

На ЦеПП, конечно, можно все что угодно завернуть, вплоть до того, что "чтение" из локальной переменной будет единственным оператром функции main() нетривиальной программы в сотню мегабайт. Только тип у этой переменной не будет int.

Die-Hard ★★★★★
() автор топика
Ответ на: комментарий от Die-Hard

Это как раз таки именно Це, то что я написал. Я ж конкретный пример с портом привёл. Ведь из этого примера понятно, почему чтение i и j в разном порядке может привести к разным результатам. Вполне реальный пример. С объектами-то понятно, но речь о том, что и в Це это вполне реально, и именно для этого и был придуман собственно volatile, а не для потоков (тут могу ошибаться, но этот вопрос уже представляет сугубо исторический интерес).

Собственно, без всех этих подробностей, можно ответить так: "стандарт требует". На то и volatile, чтоб было чётко понятно, в какие моменты времени будет прочитана и записана эта переменная, и будет ли она прочитана вообще, не отоптимизирует ли её компилятор нафиг. Выше уже говорилось про sequence points.

Teak ★★★★★
()
Ответ на: комментарий от Die-Hard

> Это не Це, что ты описАл.

блин, ну какой не Це, если volatile именно так и устроен. Или ты что, считаешь что volatile придумали специально для переменных shared между тредами?? Вот как раз нет.

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

dilmah:

> приведи пожалуйста определение volatile.

Модификатор, предписывающий компилятору не делать никаких предположений о текущем значении переменной.

Каким боком отсюда может получится, что _чтение_ одной переменной может повлиять на значение другой переменной? Чтобы программа поменяла свое состояние, переменная должна хотя бы быть прочитанной _куда-то_, чтобы хоть что-нибудь изменилось. Операция же i == j с точки зрения логики программы атомарна.

Ладно, я уже понял, откуда эта глупая ремарка вылазит: из буквального следования формальным правилам ("чтение волатильных переменных может иметь сайд-эффект").

Die-Hard ★★★★★
() автор топика
Ответ на: комментарий от Die-Hard

Я не понял, почему так упорно, уже второй пост подряд, игнорируется мой пример с портом? Конкретный пример, когда "глупое формальное правило" перестаёт быть таким уж глупым и формальным. Или у нас ввод-вывод уже отменили? Или чтение из-портов никакого сайд-эффекта никогда не имеет?

Teak ★★★★★
()
Ответ на: комментарий от Die-Hard

Мы, похоже, по-разному понимаем слово "порт".

Это не объект C++. Это какое-то устройство (железка), которое управляется посредством чтения-записи в определённую область памяти. То есть i - это в моём примере область памяти, через которую можно последовательно считывать данные, размером как раз с int, а j - это ещё одна область памяти, в которой можно прочитать, сколько раз ты считал данные из j (некий счётчик). При определённой фантазии можно представить себе компьютер, в котором отображение управляющих регистров этой железки на память можно произвольно менять соответствующим системным вызовом, в том числе даже сделать так, чтоб она управлялась через автоматические стэковые переменные :) Типа: volatile i, j; device_set_register_addresses(&i, &j); и можем писать/читать прямо в локальные переменные :) Изврат конечно, но кто сказал что это нельзя? И как компилятор должен угадать, что тут как раз не такой случай? Следить, передавались ли куда-нибудь адреса этих переменных? :) Так я тут же придумаю другой пример, похлеще.

А прочитав при таком раскладе i раньше j, получим j на единицу больше, чем если i читать после j.

Teak ★★★★★
()
Ответ на: комментарий от Teak

И дело даже не в том, что я придумаю такой пример, а в том что при наличии модификатора volatile компилятор _НЕ_ДОЛЖЕН_ ничего пытаться предсказать. Он должен тупо взять и прочитать переменные, каждую к следующей контрольной точке (запятой, ||, &&, концу оператора, что там ещё бывает), при чём порядок их вычисления (т.е. чтения) также не должен у него вызывать никакого сомнения.

Teak ★★★★★
()
Ответ на: комментарий от Die-Hard

Операция ( i == j) ведь выполняется примерно так:

mov i в регистр1 mov j в регистр2 cmp р1,р2

А volatile - просто спецификатор, который говорит компилятору, что НЕЛЬЗЯ сохранять значение этой переменной в регистре, а нужно каждый раз считывать из памяти. А это невыполнимо при сравнении двух volatile. Хоть маленькая, да срачная вероятность того, что переменная изменится есть (: Так что я не уверен в ее атомарности. Почему она должна быть атомарной?

Chumka ★★★
()
Ответ на: комментарий от Chumka

> А volatile - просто спецификатор, который говорит компилятору, что НЕЛЬЗЯ сохранять значение этой переменной в регистре,

имхо, немножко не так. Стандарт Си вообще-то вряд ли оперирует терминами типа "регистр", потому что это деталь реализации. Поэтому семантика volatile более тонкая.

На RISC машинах вообще нельзя делать никаких операций с памятью кроме load и store. То есть чтобы сделать любую операцию нужно сперва загрузить в регистр.

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

>Стандарт Си вообще-то вряд ли оперирует терминами типа "регистр", потому что это деталь реализации

Здрасьте ;)

про модификатор register слышали ?

Он правда не _гарантирует_ размещение переменной в регистре но уж точно данная ситуация не является "деталью реализации"

volatile же подразумевает что значение переменной может быть изменено "неявным образом" (не средствами текущей программы). и указывает компилятору что данную переменную нельзя оптимизировать. Eсли речь идёт о openmp компиляторе то там свои средства оптимизации и указания доступности переменных.

PS: Смысла в использовании volatile кроме случаев, когда _явно_ существует изменение переменной _неявным_ образом не вижу, потому как данный модификатор мешает оптимизации.

sS ★★★★★
()
Ответ на: комментарий от anonymous

>Пардон: volatile int i; volatile int j;

ROTFL ;))

Домашнее задание:

запусти icc -S для обоих вариантов а потом сравни результаты ;)

sS ★★★★★
()

Спасибо всем откликнувшимся, особенно sS.

Я все написАл; все работает, как мне надо.

Die-Hard ★★★★★
() автор топика

по-моему, самый простой способ, это временная переменная:

volatile int i,j; int temp;

if (temp = i, temp == j) ...

idle ★★★★★
()
Ответ на: комментарий от Die-Hard

2Die-Hard

а у тебя есть понимание, что коды

volatile int i,j;

if(i == j){...

и

volatile int i,j;

if(j == i){...

могут дать различные результаты?

anonymous
()
Ответ на: комментарий от sS

> Здрасьте ;) про модификатор register слышали ?

ну он просто так называется:) Никакой жестко прописанной связи с регистрами машины стандарт не предписывает. Регистров может вообще не быть, может у вас стековый процессор..

dilmah ★★★★★
()
Ответ на: комментарий от Die-Hard

Die-Hard:

А что насчет явных барьеров? Будет и быстрее (компилятор между барьерами сможет оптимизировать) и понятнее и матов не будет. Или в icc нечто подобное asm("":::"memory") не сработает?

Murr ★★
()
Ответ на: комментарий от sS

> ;)))

> Нужно тогда сразу

> if (i==j && j==i)

а почему не if (i==j || j==i) ?

слушай sS, а ты то понимаешь что в ДАННОМ случае от порядка следования операндов в опирации сравнения зависит результат или тупишь сегодня как Die-Hard?

а есть понимание что

volatile int i;

if(i == i){...

не всегда выполняется? потому что если нет, шагом марш в школу

anonymous
()
Ответ на: комментарий от anonymous

Лупу возьми, да, раз аж 3-х смайликов не видно и не хами старшим.

Возьми и почитай стандарт... volatile запрет на оптимизацию. Точка. Больше это не значит НИЧЕГО.

A volatile object is one that may be modified outside of program control. Memory-mapped I/O ports are a typical example. Declaring an object as volatile indicates that the compiler should always generate code to fetch the object's value from its actual memory location - it may have changed since the last access by the program. (This disallows optimizations which could load the value into a register and possibly return erroneous results.)

sS ★★★★★
()
Ответ на: комментарий от sS

думается мне (и это истинно) что куда более важно здесь

A volatile object is one that may be modified outside of program control. Memory-mapped I/O ports are a typi.....

запрет на оптимизацию всего навсего следствие подобного свойства (Возьми и почитай стандарт (с)), из чего фраза Die-Hard

> И что? Как это утверждение связано с порядком выполнения операндов?

показывает не полную ясность в этом вопросе (без наёздов, просто хочется помочь разобраться в причинах возникновения неприятной ситуации: возникновения замечания)

Есть ощущение (а мир нам дан в ощущениях) что со стороны Die-Hard имеется недопонимание фундоментальных вопросов, что для меня странно, поскольку по форуме мне известен Die-Hard, как компетентнейший товарисч. Когда же реч заходит о базовых понятиях, тут знаете не до шуток, не до смайликов..... и при том, что лупа для их рассматривания мне не нужна, выглядят они в этом контексте улыбкой князя Мышкина.

anonymous
()
Ответ на: комментарий от sS

anonymous прав.

Потому что, действительно, если на его вопрос:

> а есть понимание что > volatile int i; > if(i == i){... > не всегда выполняется? потому что если нет, шагом марш в школу

ответ отрицателен, то человек не понимает базовых вещей. Но, по моему, все здесь понимают что ответ да..

dilmah ★★★★★
()
Ответ на: комментарий от Murr

2Murr:

> А что насчет явных барьеров?

Не понял идею...

Как барьеры могут заменить волатильность переменныех?
Или ты имеешь в виду нечто типа

int i,j;
...
asm("":::"memory");
if(i == j)...

?






Die-Hard ★★★★★
() автор топика
Ответ на: комментарий от dilmah

dilmah:

>> а есть понимание что > volatile int i; > if(i == i){... > не всегда выполняется? потому что если нет, шагом марш в школу

>ответ отрицателен, то человек не понимает базовых вещей.

Могу еще и более страшную вешь сказать: if(i == i) НЕ всегда выполняется даже БЕЗ volatile!

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

Die-Hard ★★★★★
() автор топика
Ответ на: комментарий от Die-Hard

> Могу еще и более страшную вешь сказать: if(i == i) НЕ всегда > выполняется даже БЕЗ volatile!

это просто следствие undefined behaviour:)

dilmah ★★★★★
()
Ответ на: комментарий от Die-Hard

>Могу еще и более страшную вешь сказать: if(i == i) НЕ всегда выполняется даже БЕЗ volatile!

в целом судить не берусь, однако в частности возражу тебе. Частность - это gcc

int main(void){
    return 0;
}
gcc -S test.c
я опущу то, что к делу не относится
main:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
	andl	$-16, %esp
	movl	$0, %eax
	subl	%eax, %esp
	movl	$0, %eax
	leave
	ret

Этот кусок нам надо только для того чтобы от него отталкиваться, 
наблюдая изменения мо мере резвития событий.
Следующий шаг

int main(void){
    int i ;
    if (i == i) 
    {
        return 1;
    }
    return 0;
}

и asm:

main:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
	andl	$-16, %esp
	movl	$0, %eax
	subl	%eax, %esp
	movl	$1, %eax
	leave
	ret

как видно опирацией сравнения здесь и не пахнет, хочу обратить ваше внимание что никакая оптимизация не использовалась
и третий пример:

int main(void)
{
    volatile int i;    
    if (i == i) 
    {
        return 1;
    }
    return 0;
}

main:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
	andl	$-16, %esp
	movl	$0, %eax
	subl	%eax, %esp
	movl	-4(%ebp), %edx
	movl	-4(%ebp), %eax
	cmpl	%eax, %edx
	jne	.L2
	movl	$1, -8(%ebp)
	jmp	.L1
.L2:
	movl	$0, -8(%ebp)
.L1:
	movl	-8(%ebp), %eax
	leave
	ret

как говориться почувствуйте разницу. 
Это я к тому что в случае gcc if(i == i) всегда не ноль,
так вот

anonymous
()
Ответ на: комментарий от anonymous

anonymous (*) (14.02.2005 21:10:25):

> в целом судить не берусь, однако в частности возражу тебе.

Однако, я не утверждал "всегда не ...". Я говорил " не всегда ...", так что не понимаю возражения.

Die-Hard ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.