Почему функции абсолютного значения в C не принимают константные входные данные?

23

В C прототипом функции абсолютного значения (которая принимает число с плавающей запятой) является

 float fabsf( float );

Почему этот прототип не принимает постоянное значение, например так:

 float fabsf( float const );

fabsf не изменит значение ввода, не так ли?

Если у меня есть функция, которая принимает ввод и вызывает fabsf, я вынужден избегать указания ввода как const?

Как правильно обращаться с константностью в этой ситуации?

user24205
источник
26
constздесь избыточно, что, по-вашему, происходит?
ММ
1
@ ММ Я ожидаю, что это приведет к ошибке времени компиляции, если я попытаюсь изменить значение ввода внутри функции. Это неверно?
user24205
16
Поскольку параметр внутри функции является локальной копией, добавление constсовершенно бессмысленно.
Лундин
1
« fabsf не изменит значение ввода, не так ли? » Как вы могли бы сказать? Параметр передается по значению.
Дэвид Шварц
Следующий код является допустимым C: float const x = -1.0; float y = fabsf(x);так что мне кажется, что fabsf он принимает входные данные const. Невозможно сказать: «Вы можете передать мне floatпо значению, но вы не можете передать const float». (И, как мы видим из ответов, C не предоставляет способ требовать , чтобы входные данные для функции были a float const.)
Дэвид К

Ответы:

14

редактировать

Как отметил М., от параметров в прототипахconst игнорируются. Отредактированный источник исходного ответа (см. Ниже) показывает это:

float correct(float const value);

float erroneous(float const value);

float changer(float value);

float correct(float value) {
  return -value;
}

float erroneous(float value) {
  value = -value;
  return value;
}

float changer(float value) {
    value = -value;
    return value;
}

Там нет сообщения об ошибке.

В любом случае, я оставлю оригинал на месте в надежде, что он поможет.


оригинал

Параметр constat делает этот параметр доступным только для чтения внутри функции.

Например:

float correct(float const value) {
  return -value;
}

float erroneous(float const value) {
  value = -value;
  return value;
}

float changer(float value) {
  value = -value;
  return value;
}

Этот источник не будет компилироваться без сообщения об ошибке.

Функция correct()прочитает данное значение, изменит его знак и вернет отрицательное значение.

erroneous()Кажется, что функция делает то же самое, за исключением того, что этому параметру присваивается значение. Но в качестве параметра constэто не допускается.

Далее функция changer()будет работать как раньше, но не дает ошибок.

Давайте посмотрим на сайт вызова:

float f = 3.14159;
float g = correct(f); // or erroneous(f) or changer(f)

Переменная, fзаданная в качестве аргумента, будет скопирована в параметр value. Он никогда не изменится, даже если changer()будет вызван.

Вы можете посмотреть на параметры как на какие-то локальные переменные. На самом деле они в основном обрабатываются так в сгенерированном машинном коде.


Итак, почему ты видишь constиногда? Вы видите это, если указатель определен как параметр.

Если вы не хотите, чтобы значение, на которое указывает указатель, было изменено, вам нужно добавить const; но делай это в правильном положении!

void effective(int const * pointer);

void futile(int * const pointer);

void possible_but_overly_restricted(int const * const pointer);
занятая пчела
источник
Речь идет о прототипах, хотя прототип не float fabsf( float const );имеет ничего общего с реализацией функции (которая не должна повторять const), на самом деле constона полностью игнорируется в прототипе
MM
2
Может ли const войти в определения функций, не заходя в прототип?
user24205
3
@ user24205 да, может
Даниэль Жур
33

C использует проход по значению. Значение параметра функции является копией аргумента, который вы даете.

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

Это похоже на назначение:

const float f = 5.5f;
float g = f;   // OK

Фактически, в языке указывается, что значением выражения никогда не может быть const, т. Е. Когда значение читается из переменной, это значение отсутствует, constдаже если переменная была.

М.М.
источник
8

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

Это означает, что с точки зрения звонящего float fabsf( float );и float fabsf( const float );совпадают. Так что нет смысла делать параметр const.

Здесь имеет смысл использовать const, если передаваемый параметр является указателем, например:

void print_string(char *str)

Эта функция, несмотря на то, что предлагает имя, может разыменовать данный указатель и изменить то, на что он указывает, т. str[0] = 'x'Е. Привести к изменению, видимому вызывающей функцией. Если бы эта функция была определена так:

void print_string(const char *str)

Вызывающая сторона гарантирует, что функция не может выполнять какие-либо изменения в том, на что strуказывает.

dbush
источник
«Абоненту гарантировано, что функция не может выполнять какие-либо изменения ...» не соответствует действительности. Функция знает адрес данных и , следовательно , может изменить его, с, например ((char*)str)[0] = 'f'. Поэтому const ... *в списке аргументов есть только «декларация о намерениях».
oromoiluig
5

Чтобы добавить точку зрения юриста по языку:

Для совместимости двух типов функций оба должны указывать совместимые типы возвращаемых данных. Кроме того, списки типов параметров, если они присутствуют, должны согласовываться по количеству параметров и при использовании терминатора многоточия; соответствующие параметры должны иметь совместимые типы . [..] При определении совместимости типов и составного типа [..] каждый параметр, объявленный с квалифицированным типом, принимается как имеющий неквалифицированную версию своего объявленного типа .

N1570 6.7.6.3/15

Это означает, что эти два совместимы:

void foo(int const);
void foo(int);

Поэтому вы можете написать прототип с или без const(что означает, что без имеет больше смысла; меньше для ввода / чтения) и можете добавить constопределение функции, если вы хотите избежать случайного изменения параметра (copyied - call by value!) Внутри функций. тело.

Даниэль Жур
источник