Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Порядок выполнения операций. Вопрос зантокам!
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
igorenja
Что сделает компилятор увидев такой код:
Код
twi_write_data(0,ptr, data[ptr++]);
HARMHARM
Сделает вызов функции. Если найдет соответствующий заголовок.
Объясните свой вопрос. Зантоки и телепаты в отпуске.
igorenja
Цитата(HARMHARM @ Nov 11 2009, 12:45) *
Сделает вызов функции. Если найдет соответствующий заголовок.
Объясните свой вопрос. Зантоки и телепаты в отпуске.



Допустип ptr==0, с какими параметрами будет вызвана функция twi_write_data()
Dima_G
Цитата(igorenja @ Nov 11 2009, 10:33) *
Что сделает компилятор увидев такой код:
Код
twi_write_data(0,ptr, data[ptr++]);


Компилятор - скомпилирует. А вот что сделает программа - не определено, тк компиляторозависимо.
Вобщем - бэдстайл
GetSmart
Так писать ИМХО не рекомендуется. А вообще, умный компилятор на такое должен выдавать варнинг, аналогичный как при чтении двух и более волатильных переменных в одной операции.

ЗЫ. На форуме уже была оч похожая тема, но там был прикол с присвоением выражения толи ++n, толи n++.
LessNik
Цитата(igorenja @ Nov 11 2009, 09:33) *
Что сделает компилятор увидев такой код:
Код
twi_write_data(0,ptr, data[ptr++]);


У меня выдаёт предупреждение:
Warning[Pa081]: undefined behavior: the order of read and modification of variable "ptr" (or a value reached by some form of indirection through it) is undefined in this statement
igorenja
Цитата(LessNik @ Nov 11 2009, 13:53) *
У меня выдаёт предупреждение:
Warning[Pa081]: undefined behavior: the order of read and modification of variable "ptr" (or a value reached by some form of indirection through it) is undefined in this statement



Мой ИАР 4.41 скомпилировал и не выдал ни каких продупреждений.
В итоге работало это вот так:
Код
twi_write_data(0,ptr+1, data[ptr]);

На запись:
Код
twi_write_data(0,ptr++, data[ptr]);

выдаёт предупреждение...
Короче говоря единственно правильный вариант:
Код
twi_write_data(0,ptr, data[ptr]);
ptr++;
_Pasha
Цитата
Never rely on argument's order.

Такую татуировку на лоб обычно рекомендуют сделать экспериментаторам.
HARMHARM
Цитата(igorenja @ Nov 11 2009, 10:02) *
Короче говоря единственно правильный вариант:
Код
twi_write_data(0,ptr, data[ptr]);
ptr++;

Вообще-то правильнее привыкнуть писать в таких местах ++ptr. Потому что ptr может оказаться сложным типом, при ptr++ может быть создана лишняя копия.
Dima_G
Цитата(HARMHARM @ Nov 11 2009, 13:45) *
Вообще-то правильнее привыкнуть писать в таких местах ++ptr. Потому что ptr может оказаться сложным типом, при ptr++ может быть создана лишняя копия.


Кстати, да.
Из той же серии - полезно писать
for ( ...; ++clVariable_)

Хотя, для части людей сложно поверить в то, что конструкции
for (int i=0; i<10; ++i)
и
for (int i=0; i<10; i++)
Функционально одинаковы, но первая - оптимальнее biggrin.gif
esaulenka
HARMHARM, а можно пример?
Не понимаю...
Dima_G
Цитата(esaulenka @ Nov 11 2009, 15:37) *
HARMHARM, а можно пример?
Не понимаю...


надеюсь, ув. HARMHARM не будет против, если я отвечу smile.gif

на пальцах - в случае постинкремента мы
1) изменяем состояние объекта
2) возвращаем предыдущее состояние объекта (вот для сохрения предыдущего состояния как раз и создается копия)

в случае прединкремента мы
1) изменяем состояние объекта
2) возвращаем новое состояние - сохранять старое состояние объекта не требуется
GetSmart
Эта особенность инкремента была актуальна в прошлом веке. Особенно для AVR. Приличные компиляторы (ARM) вне зависимости от варианта инкремента делают одинаковый по размеру и скорости код. Так что не актуально.
Demeny
Цитата(Dima_G @ Nov 11 2009, 15:34) *
Хотя, для части людей сложно поверить в то, что конструкции
for (int i=0; i<10; ++i)
и
for (int i=0; i<10; i++)
Функционально одинаковы, но первая - оптимальнее biggrin.gif

Бред какой ...
Только что проделал такое с VC 6. Результирующий exe-файл в обоих случаях идентичный (проверено тотал коммандером).
esaulenka
Никогда не задумывался...

Но разве ptr++ - это не "сначала использовать переменную ptr, а потом её инкрементировать", а именно "создать копию, инкрементировать один экземпляр, а использовать другой" ?

К тому же, на мой взгляд, i++ читается лучше, чем ++i. Во всяком случае, я когда вижу ++i, начинаю задумываться, зачем оно тут применяется smile.gif
Dima_G
Цитата(Demeny @ Nov 11 2009, 16:55) *
Бред какой ...
Только что проделал такое с VC 6. Результирующий exe-файл в обоих случаях идентичный (проверено тотал коммандером).


Потому, что умный компилятор соптимизировал. Но не слишком надейтесь на то, что так будет всегда. Попробуйте проверить с объектом класса с определенным оператором пост и прединкремента
GetSmart
Цитата(Dima_G @ Nov 11 2009, 22:15) *
...Но не слишком надейтесь на то, что так будет всегда...

В 2012-ом все компиляторы дружно разучатся оптимизировать biggrin.gif
Dima_G
Цитата(GetSmart @ Nov 11 2009, 20:28) *
В 2012-ом все компиляторы дружно разучатся оптимизировать biggrin.gif


Имелось в виду - при смене компилятора / платформы / типа данных laughing.gif
zltigo
Цитата(Dima_G @ Nov 11 2009, 19:15) *
Потому, что умный компилятор соптимизировал.

А дураки среди компиляторов вымирают, посему пересказывать байки начала 90x не надо. Поздно.
Цитата
Попробуйте проверить с объектом класса с определенным оператором пост и прединкремента

"определенным" это то, что люди называют перегруженным оператором? Это во-первых C++, а во-вторых еще проще для оптимизатора, ибо по стандарту перегрузка оператора заменяется на вызов функции - и никаких фантазий для неправильной оптимизации вообще нет. Нут тебe и железнейшая sequence points еще до кучи.
Dima_G
Цитата(zltigo @ Nov 11 2009, 20:41) *
А дураки среди компиляторов вымирают, посему пересказывать байки начала 90x не надо. Поздно.

"определенным" это то, что люди называют перегруженным оператором? Это во-первых C++, а во-вторых еще проще для оптимизатора, ибо по стандарту перегрузка оператора заменяется на вызов функции - и никаких фантазий для неправильной оптимизации вообще нет. Нут тебe и железнейшая sequence points еще до кучи.


Да, перегруженным.
Вот пример класса. В нем перегружены операторы инкремента

CODE
#include <stdio.h>
#include <time.h>
#include <sys/time.h>

typedef struct timeval TTime;

/////////////////////////////////////////////////
class ClTest
{
public:
int aiBuf_m[1024];

ClTest()
{
aiBuf_m[0] = 0;
}

//Prefix form of increment
ClTest& operator ++()
{
++aiBuf_m[0];
return *this;
}

//Postfix form of increment
ClTest operator ++(int)
{
ClTest clRetValue_ = *this;
++aiBuf_m[0];
return clRetValue_;
}
};

/////////////////////////////////////////////////
unsigned int GetInterval(TTime* psBegin_, TTime* psEnd_)
{
return (psEnd_->tv_usec - psBegin_->tv_usec) + (psEnd_->tv_sec - psBegin_->tv_sec)*1000000;
}

/////////////////////////////////////////////////
int main()
{
TTime sBeginTime_, sEndTime_;
static const unsigned int ITTERATIONS_CNT = 100000;

{
ClTest clTest_;

gettimeofday(&sBeginTime_, NULL);

for (;clTest_.aiBuf_m[0] != ITTERATIONS_CNT; ++clTest_)
continue;

gettimeofday(&sEndTime_, NULL);

printf("Prefix form: time = %u\n", GetInterval(&sBeginTime_, &sEndTime_));
}

{
ClTest clTest_;

gettimeofday(&sBeginTime_, NULL);

for (;clTest_.aiBuf_m[0] != ITTERATIONS_CNT; clTest_++)
continue;

gettimeofday(&sEndTime_, NULL);

printf("Postfix form: time = %u\n", GetInterval(&sBeginTime_, &sEndTime_));
}

return 0;
}


Вот результат его работы (GCC 4.1.2, оптимизация выключена):
Цитата
Prefix form: time = 520
Postfix form: time = 116160


Естественно, при включенной оптимизации эти значения выравниваются. Но не факт, что оптимизация пройдет на более сложных примерах.
Слышал, что люди, хорошо владеющие STL и тп вещами, аккуратнее относятся к пост и пред инкременту.


Собственно, немного изменил пример, и GCC на оптимизации O3 сдулся

Цитата
Prefix form: time = 68
Postfix form: time = 89358


CODE
{
ClTest clTest_;
volatile int i;

gettimeofday(&sBeginTime_, NULL);

for (;clTest_.aiBuf_m[0] != ITTERATIONS_CNT; )
i = (++clTest_).aiBuf_m[0];

gettimeofday(&sEndTime_, NULL);

printf("Prefix form: time = %u\n", GetInterval(&sBeginTime_, &sEndTime_));
}

{
ClTest clTest_;
volatile int i;

gettimeofday(&sBeginTime_, NULL);

for (;clTest_.aiBuf_m[0] != ITTERATIONS_CNT; )
i = (clTest_++).aiBuf_m[0];

gettimeofday(&sEndTime_, NULL);

printf("Postfix form: time = %u\n", GetInterval(&sBeginTime_, &sEndTime_));
}
GetSmart
Кстати, во FreeRTOS встречаются оба варианта инкремента (без доп. действий) одинакого часто. Автор мечется в сомнении ?! biggrin.gif
Flexz
FreeRTOS просто, видимо, разные люди пишут smile.gif
У Страуструпа, кстати, там где int - постинкремент, а там где итератор - прединкремент
HARMHARM
Цитата(Flexz @ Nov 12 2009, 09:56) *
FreeRTOS просто, видимо, разные люди пишут smile.gif

Нет, там один человек. Впрочем, по коду, который долгое время эволюционирует, можно проследить как эволюционирует сам программист smile.gif
Dima_G
Цитата(Flexz @ Nov 12 2009, 11:56) *
У Страуструпа, кстати, там где int - постинкремент, а там где итератор - прединкремент

Со встроенными типами практически всегда это без разницы - компилятор соптимизирует smile.gif (хотя, вдруг выйдет новая интересная платформа + сырой комиплятор rolleyes.gif )

Но лично мне не нравится такой зоопрак из ++i и i++ в программе sad.gif
Поэтому пишу единообразно, используя ++i
_Pasha
Цитата(Dima_G @ Nov 12 2009, 12:00) *
Но лично мне не нравится такой зоопрак из ++i и i++ в программе sad.gif
Поэтому пишу единообразно, используя ++i

Ладно-ладно. А volatile-переменные тоже по-умному "додумываются" ? Или все-таки есть разница? wink.gif
Dima_G
Цитата(_Pasha @ Nov 12 2009, 19:32) *
Ладно-ладно. А volatile-переменные тоже по-умному "додумываются" ? Или все-таки есть разница? wink.gif

rolleyes.gif
Чет не пойму, что Вы имеете в виду laughing.gif
defunct
Цитата(igorenja @ Nov 11 2009, 10:02) *
Короче говоря единственно правильный вариант:
Код
twi_write_data(0,ptr, data[ptr]);
ptr++;

До единственно правильного далеко т.к. есть пара вопросов:
1. На кой в twi_write_data передавать "ptr"?
2. На кой индекс неверно обзывать поинтером?

Два единственно правильных варианта:

- twi_write_data( 0, *ptr++ )
- twi_write_data( 0, data[ i++ ] );
_Pasha
Цитата(Dima_G @ Nov 13 2009, 06:18) *
rolleyes.gif
Чет не пойму, что Вы имеете в виду laughing.gif

Коль скоро для volatile оптимизации запрещены, то разница между ++j и j++ (volatile j) должна наблюдаться на любых компиляторах.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.