[plain c] Параметр функции как const и не const при вызове.
От: DirtyGarry  
Дата: 21.04.15 09:59
Оценка:
Прототип функции описывается так

int func(unsigned int *c, const unsigned int *a, const unsigned int *b);


Функция часто вызывается так

rc = func(c, c, b);


Т.е. параметр с одновременно является и константой и не константой. Могут ли в этой ситуации возникнуть какие-нибудь "грабли"?

Спасибо
Re: [plain c] Параметр функции как const и не const при вызове.
От: uzhas Ниоткуда  
Дата: 21.04.15 10:06
Оценка:
Здравствуйте, DirtyGarry, Вы писали:

DG>Т.е. параметр с одновременно является и константой и не константой. Могут ли в этой ситуации возникнуть какие-нибудь "грабли"?


грабли называются strict aliasing
http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule
Re[2]: [plain c] Параметр функции как const и не const при вызове.
От: Alexander G Украина  
Дата: 21.04.15 10:14
Оценка: +1
Здравствуйте, uzhas, Вы писали:

U>грабли называются strict aliasing

U>http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule

Ну так это в данном случае корректный alias

a cv-qualified version of the dynamic type of the object


не?
Русский военный корабль идёт ко дну!
Re[2]: [plain c] Параметр функции как const и не const при вызове.
От: night beast СССР  
Дата: 21.04.15 10:16
Оценка:
Здравствуйте, uzhas, Вы писали:

DG>>Т.е. параметр с одновременно является и константой и не константой. Могут ли в этой ситуации возникнуть какие-нибудь "грабли"?


U>грабли называются strict aliasing

U>http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule

почему?
указатели же не помечены как restrict
Re[3]: [plain c] Параметр функции как const и не const при в
От: uzhas Ниоткуда  
Дата: 21.04.15 11:06
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Ну так это в данном случае корректный alias


согласен, на эти грабли тут не наступим
имелся в виду aliasing в широком смысле : http://en.wikipedia.org/wiki/Aliasing_(computing)
хотел обратить внимание на такой вариант: у функции f могут быть неявные предположения как соотносятся входные указатели. то есть могут ли они указывать на одну память или обязаны не иметь пересекающихся участков
const/non const здесь неважен
я сталкивался с такой ситуацией
есть функция double f(double& a, double& b)

если ее вызвать, как
double a = 0;
double b = 0;
double x = f(a, b); <-- здесь корректное x


а при вызове

double a = 0;
double x = f(a, a); <-- здесь некорректное x


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

пример:
double Return1And2(double& a, double& b)
{
  a = 1.0;
  b = 2.0;
  return a;
}


эта функция возвращает 1, если входные параметры лежат в разных областях памяти. иначе возвращает 2.0
Отредактировано 21.04.2015 11:16 uzhas . Предыдущая версия .
Re: [plain c] Параметр функции как const и не const при вызове.
От: Pavel Dvorkin Россия  
Дата: 21.04.15 11:30
Оценка:
Здравствуйте, DirtyGarry, Вы писали:

DG>Т.е. параметр с одновременно является и константой и не константой. Могут ли в этой ситуации возникнуть какие-нибудь "грабли"?


void func(unsigned int *c, const unsigned int *a)
{
    printf("%d\n",a[0]); // 8888
    c[0] = 9999;
    printf("%d\n",a[0]); // why 9999 ? a is const unsigned int* , how a[0] was changed ?

}

int _tmain(int argc, _TCHAR* argv[])
{
    unsigned c[] = {8888};
    func(c,c);
    return 0;
}
With best regards
Pavel Dvorkin
Re: [plain c] Параметр функции как const и не const при вызове.
От: Evgeny.Panasyuk Россия  
Дата: 21.04.15 11:51
Оценка: +1
Здравствуйте, DirtyGarry, Вы писали:

DG>Т.е. параметр с одновременно является и константой и не константой. Могут ли в этой ситуации возникнуть какие-нибудь "грабли"?


Зависит от контракта функции.

Тут сразу вспоминается случай с memcpy:
void* memcpy( void* dest, const void* src, std::size_t count );
// If the objects overlap, the behavior is undefined.
После оптимизации glibc одно UB#1 заменилось другим UB#2. Но некоторый код закладывался на то что у memcpy UB#1, хотя этого делать не должен был, и был совершенно не готов работать с UB#2.
Re[2]: [plain c] Параметр функции как const и не const при вызове.
От: DirtyGarry  
Дата: 21.04.15 14:09
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Зависит от контракта функции.


Логика func такова, что новое значение c получается на основе значения a.
Re[3]: [plain c] Параметр функции как const и не const при в
От: Evgeny.Panasyuk Россия  
Дата: 21.04.15 14:45
Оценка:
Здравствуйте, DirtyGarry, Вы писали:

EP>>Зависит от контракта функции.

DG>Логика func такова, что новое значение c получается на основе значения a.

Этих сведений недостаточно для того чтобы утверждать есть ли в func(c, c, b) баг или нет. Нужно уточнить контракт.

Например если func это сложение векторов, то есть у неё внутри:
int func(unsigned int *c, const unsigned int *a, const unsigned int *b)
{
    for( ... )
        c[i] = a[i] + b[i];
}
тогда делать вызов func(c, c, b) можно. Но опять таки — помимо кода нужно смотреть контракт.
Отредактировано 21.04.2015 14:45 Evgeny.Panasyuk . Предыдущая версия .
Re[4]: [plain c] Параметр функции как const и не const при в
От: DirtyGarry  
Дата: 21.04.15 15:32
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP> Но опять таки — помимо кода нужно смотреть контракт.


Не могли бы Вы пояснить, что именно Вы понимаете под "контрактом"? Как и в каких условиях функция func вызывается?
Re[5]: [plain c] Параметр функции как const и не const при в
От: Evgeny.Panasyuk Россия  
Дата: 21.04.15 15:54
Оценка: +1
Здравствуйте, DirtyGarry, Вы писали:

EP>> Но опять таки — помимо кода нужно смотреть контракт.

DG>Не могли бы Вы пояснить, что именно Вы понимаете под "контрактом"? Как и в каких условиях функция func вызывается?

Контракт функции включает:

1. Условия, называемые предусловиями, которые должны быть выполнены перед вызовом функции (включая ограничения накладываемые на аргументы, а возможно и на глобальное состояние). Если эти условия не выполнены, то наступает undefined behaviour — может произойти что угодно.
Например одно из предусловий двоичного поиска звучит как "входной массив должен быть отсортирован".

2. Постусловия — задают то, в какое состояние функция обещает перевести систему/данные/etc в том случае, если предусловия были выполнены. Например двоичный поиск, при входных данных удовлетворяющих предусловию, обязуется найти соответствующий элемент.


Если же брать вышеописанный пример сложения векторов — то даже если текущая реализация корректно работает для func(c, c, b), но в контракте записано что все три диапазона не должны пересекаться — то автор функции имеет право, согласно контракту, поменять код функции таким образом, что func(c, c, b) уже работать не будет.
Аналогичная ситуация произошла с memcpy — её реализацию поменяли, не изменяя при этом контракт — но как оказалось были такие программы, которые закладывались на детали реализации memcpy не относящиеся к контракту, что привело к undefined behaviour.
Re[4]: [plain c] Параметр функции как const и не const при в
От: Ops Россия  
Дата: 21.04.15 21:06
Оценка:
Здравствуйте, uzhas, Вы писали:

U>эта функция возвращает 1, если входные параметры лежат в разных областях памяти. иначе возвращает 2.0


Это какой-то экзотический сценарий, имхо, чтобы такую функцию именно так использовали не по ошибке.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[5]: [plain c] Параметр функции как const и не const при в
От: uzhas Ниоткуда  
Дата: 22.04.15 08:12
Оценка: +1
Здравствуйте, Ops, Вы писали:

Ops>Это какой-то экзотический сценарий, имхо, чтобы такую функцию именно так использовали не по ошибке.


ну почему же
функция возвращает три числа разными путями. иногда есть заинтересованность получить лишь одно
double dummy;
double interestedValue = f(dummy, dummy);
Re: [plain c] Параметр функции как const и не const при вызове.
От: DirtyGarry  
Дата: 05.09.15 06:21
Оценка:
Коллеги, спасибо за ваши ответы по исходной задаче.

Давайте теперь немного усложним условие. Пусть у func будет вот такой прототип

int func(restrict unsigned int *c, const restrict unsigned int *a, const restrict unsigned int *b);


При таком вызове

rc = func(c, c, b);


получается, что требование, накладываемое restrict, нарушается и получается неопределенное поведение. Или я не прав?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.