Чому функції абсолютного значення в С не приймають введення const?


23

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

 float fabsf( float );

Чому цей прототип не приймає постійне значення, як це:

 float fabsf( float const );

fabsf не змінить значення вводу, чи не так?

Якщо у мене є функція, яка приймає вхід і викликає fabsf, чи змушений я уникати введення введення як const?

Який підходящий спосіб вирішити коректність у цій ситуації?


26
constтут зайве, що ти уявляєш, що відбувається?
ММ

1
@MM Я сподіваюся, що це створить помилку часу компіляції, якби я спробував змінити значення вводу всередині функції. Це неправильно?
user24205

16
Оскільки параметр всередині функції є локальною копією, додавання constє абсолютно безглуздим.
Лундін

1
" fabsf не змінить значення вводу, чи не так? " Як ви могли сказати? Параметр передається за значенням.
Девід Шварц

Наступний код є законним C: float const x = -1.0; float y = fabsf(x);тому мені здається, що fabsf він приймає const введення. Немає способу сказати "ти можеш передати мені floatзначення за значенням, але ти не можеш передати const float". (І як ми бачимо у відповідях, C не забезпечує способу вимагати, щоб вхід до функції був a float const.)
David K

Відповіді:


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 використовує прохідне значення. Значення параметра параметра - це копія наведеного вами аргументу.

Добре копіювати як flost const, так і non-const, а результат - float без const.

Це схоже на призначення:

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

Насправді, мова вказує, що значення виразу ніколи не може бути const, тобто коли значення зчитується зі змінної, це значення constнавіть не є змінною.


8

Оскільки мова С використовує семантику передачі за значенням, будь-який аргумент, який ви передаєте їй, хоча міг би бути змінений внутрішньо, не впливає безпосередньо на значення, яке ви передаєте.

Це означає, що з точки зору абонента float fabsf( float );і float fabsf( const float );ті самі. Тож немає сенсу робити параметр const.

Де це дійсно має сенс використовувати const, якщо параметр ви передаєте покажчик, наприклад:

void print_string(char *str)

Ця функція, незважаючи на те, що пропонує ім'я, може скинути заданий покажчик і змінити те, що вказує, тобто str[0] = 'x'призвести до зміни, яку можна побачити за допомогою функції виклику. Якщо цю функцію було визначено так:

void print_string(const char *str)

Абонент переконується, що функція не може виконувати будь-які зміни того, на що strвказує.


"Користувач переконується, що функція не може виконувати жодних модифікацій ..." не відповідає дійсності. Функція знає адресу даних і , отже , може змінити його, з, наприклад ((char*)str)[0] = 'f'. Отже, const ... *список аргументів є лише "декларацією про наміри".
oromoiluig

5

Щоб додати перспективу юриста з мови:

Щоб два типи функцій були сумісні, обидва повинні вказувати сумісні типи повернення. Більше того, списки типів параметрів, якщо вони є присутніми, повинні узгоджуватися за кількістю параметрів та у використанні термінатора еліпсису; відповідні параметри повинні мати сумісні типи . [..] При визначенні сумісності типу та складеного типу [..] кожен параметр, оголошений кваліфікованим типом, вважається такою, що має некваліфіковану версію заявленого типу .

N1570 6.7.6.3/15

Це означає, що ці два сумісні:

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

Тому ви можете писати прототип з або без const(що означає без більшого сенсу; менше набирати / читати), а також можете додавати constу визначення функції, якщо ви хочете уникнути випадкового зміни параметра (скопійовано - виклик за значенням!) Всередині функцій тіло.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.