C'deki mutlak değer fonksiyonları neden sabit girişleri kabul etmiyor?


23

C de mutlak değer fonksiyonunun (bir şamandırayı kabul eden) prototipi

 float fabsf( float );

Bu prototip neden şu şekilde sabit bir değer kabul etmiyor:

 float fabsf( float const );

fabsf girişin değerini değiştirmez, değil mi?

Bir girişi kabul eden ve fabsf'yi çağıran bir fonksiyonum varsa, girişi const olarak belirtmekten kaçınmak zorunda mıyım?

Bu durumda sabit doğrulukla başa çıkmanın uygun yolu nedir?


26
constburada gereksiz, ne düşünüyorsun?
MM

1
@MM İşlev içindeki girdinin değerini değiştirmeye çalışırsam derleme zamanı hatası oluşturacağını umuyorum. Bu yanlış mı?
user24205

16
İşlevin içindeki parametre yerel bir kopya olduğundan, ekleme consttamamen anlamsızdır.
Lundin

1
fabsf girişin değerini değiştirmeyecek, değil mi? ” Nasıl söyleyebilirdiniz? Parametre değere göre geçirilir.
David Schwartz

Aşağıdaki kod yasal C: float const x = -1.0; float y = fabsf(x);o geliyor bana bu yüzden fabsf yapar const girişlerini kabul eder. "Bana bir floatdeğeri geçebilirsin ama geçemezsin" demenin bir yolu yok const float. (Ve cevaplarda gördüğümüz gibi, C bir işleve girişin a olmasını gerektirecek bir yol sağlamaz float const.)
David K

Yanıtlar:


14

Düzenle

MM yorumladığı gibi, parametrelere prototipconst göz ardı edilir. Orijinal yanıtın düzenlenmiş kaynağı (aşağıya bakın) şunu gösterir:

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;
}

Hata mesajı yok.

Her neyse, yardımcı olabileceği umuduyla orijinali yerinde bırakacağım.


orijinal

constBir parametre bu hale parametreyi salt okunur işlevi içinde.

Örneğin:

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

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

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

Bu kaynak hata mesajı olmadan derlenmeyecektir.

İşlev correct()verilen değeri okuyacak, işaretini değiştirecek ve reddedilen değeri döndürecektir.

Fonksiyon erroneous(), parametreye bir atama olması dışında, etkili bir şekilde aynısını yapıyor gibi görünmektedir. Ancak parametre olduğu constiçin buna izin verilmez.

Daha sonra, işlev changer()daha önce her ikisi gibi çalışır, ancak hata vermez.

Çağrı sitesine bakalım:

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

Bağımsız değişken olarak fverilen değişken parametreye kopyalanırvalue . Aranacak olsa bile asla değişmeyecek changer().

Parametrelere bir tür yerel değişken olarak bakmak isteyebilirsiniz. Aslında üretilen makine kodunda çoğunlukla bu şekilde kullanılırlar.


Peki, neden constbazen görüyorsun ? Bir işaretçi parametre olarak tanımlanmışsa görürsünüz .

İstemediğiniz zaman değeri işaret , eklemek gerekmez değiştirilmesi const; ama doğru pozisyonda yapın!

void effective(int const * pointer);

void futile(int * const pointer);

void possible_but_overly_restricted(int const * const pointer);

Soru prototiplerle ilgili olsa da, prototipin float fabsf( float const );işlev uygulamasıyla (bunun tekrarlanması gerekmez) hiçbir ilgisi yoktur const, aslında constprototipte tamamen göz ardı edilir
MM

2
Const, prototipe girmeden işlev tanımlarına gidebilir mi?
user24205

3
@ user24205 evet yapabilir
Daniel Jour

33

C, değere göre geçiş kullanır. Bir işlevin parametresinin değeri, verdiğiniz bağımsız değişkenin bir kopyasıdır.

Sabit ve sabit olmayan şamandıraları kopyalamak uygundur ve sonuç sabit olmayan bir şamandıradır.

Ödeve benzer:

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

Aslında, dil bir ifadenin değerinin hiçbir zaman olamayacağını belirtir const, yani bir değişkenten bir değer okunduğunda, bu değişken değişken constolsa bile bu değer değildir .


8

C dili değer semantiklerini kullandığından, dahili olarak değiştirilebildiğinde, kendisine ilettiğiniz herhangi bir argüman, ilettiğiniz değeri doğrudan etkilemez.

Bu, arayanın bakış açısından float fabsf( float );ve float fabsf( const float );aynı olduğu anlamına gelir . Yani parametreyi yapmanın bir anlamı yok const.

Nerede yapar mantıklı kullanımına constsize geçmek parametre örneğin bir işaretçi, eğer:

void print_string(char *str)

Bu işlev, adın önerdiğine rağmen, verilen işaretçiyi kaldırabilir ve işaret ettiği şeyi değiştirebilir, yani str[0] = 'x', çağıran işlev tarafından görüntülenebilir bir değişiklikle sonuçlanabilir. Bu işlev şu şekilde tanımlandıysa:

void print_string(const char *str)

Arayanın, işlevin neyi strişaret ettiği konusunda herhangi bir değişiklik yapamaması sağlanır .


"Arayanın, işlevin herhangi bir değişiklik yapamaması sağlandı ..." doğru değil. İşlev, verilerin adresini bilir ve bu nedenle, örneğin: ile değiştirebilir ((char*)str)[0] = 'f'. Bu const ... *nedenle argümanlar listesinde sadece bir "niyet beyanı" yer alır.
oromoiluig

5

Bir dil avukatı perspektifi eklemek için:

İki işlev türünün uyumlu olması için her ikisi de uyumlu dönüş türlerini belirtmelidir. Ayrıca, parametre tipi listeleri, her ikisi de mevcutsa, parametre sayısı ve üç nokta sonlandırıcısının kullanımında hemfikir olmalıdır; karşılık gelen parametreler uyumlu tiplere sahip olmalıdır . [..] Tip uyumluluğunun ve kompozit tipin belirlenmesinde, [..] nitelikli tipte beyan edilen her parametre, beyan edilen tipin niteliksiz versiyonuna sahip olarak alınır .

N1570 6.7.6.3/15

Bu, bu ikisinin uyumlu olduğu anlamına gelir:

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

Bu nedenle, prototipi kullanarak veya olmadan const(yani daha mantıklı değil; yazmak / okumak için daha az anlamına gelir) yazabilirsiniz ve constişlevlerin içinde (kopyalanan - değere göre çağrı!) Parametresini yanlışlıkla değiştirmekten kaçınmak istiyorsanız, işlev tanımına ekleyebilirsiniz . vücut.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.