Tại sao các hàm giá trị tuyệt đối trong C không chấp nhận đầu vào const?


23

Trong C, nguyên mẫu cho hàm giá trị tuyệt đối (chấp nhận float) là

 float fabsf( float );

Tại sao nguyên mẫu này không chấp nhận giá trị không đổi, như thế này:

 float fabsf( float const );

fabsf sẽ không thay đổi giá trị của đầu vào, phải không?

Nếu tôi có một chức năng chấp nhận đầu vào và gọi fabsf, tôi có bị buộc phải tránh chỉ định đầu vào là const không?

Cách thích hợp để xử lý const đúng trong tình huống này là gì?


26
constở đây là dư thừa, bạn tưởng tượng điều gì đang xảy ra?
MM

1
@MM Tôi hy vọng nó sẽ tạo ra lỗi thời gian biên dịch nếu tôi cố gắng thay đổi giá trị của đầu vào bên trong hàm. Điều này có sai không?
dùng24205

16
Vì tham số bên trong hàm là một bản sao cục bộ, việc thêm vào constlà hoàn toàn vô nghĩa.
Lundin

1
" Fabsf sẽ không thay đổi giá trị của đầu vào, phải không? " Làm thế nào bạn có thể nói? Tham số được truyền bằng giá trị.
David Schwartz

Các mã sau đây là hợp pháp C: float const x = -1.0; float y = fabsf(x);vậy có vẻ như với tôi rằng fabsf không chấp nhận đầu vào const. Không có cách nào để nói "bạn có thể vượt qua tôi floattheo giá trị nhưng bạn không thể vượt qua a const float." (Và như chúng ta thấy trong các câu trả lời, C không cung cấp cách yêu cầu đầu vào của hàm là a float const.)
David K

Câu trả lời:


14

Biên tập

Như MM nhận xét, trên các tham số trong nguyên mẫu , constbị bỏ qua. Nguồn chỉnh sửa của câu trả lời gốc (xem bên dưới) cho thấy điều này:

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

Không có thông báo lỗi.

Dù sao, tôi sẽ để nguyên bản tại chỗ với hy vọng nó có thể giúp ích.


Nguyên

Các consttại một tham số làm cho điều này tham số chỉ đọc bên trong hàm.

Ví dụ:

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

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

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

Nguồn này sẽ không biên dịch mà không có thông báo lỗi.

Hàm correct()sẽ đọc giá trị đã cho, thay đổi dấu của nó và trả về giá trị bị phủ định.

Hàm erroneous()dường như thực hiện hiệu quả như nhau, ngoại trừ việc có một phép gán cho tham số. Nhưng như tham số constnày là không được phép.

Tiếp theo, chức năng changer()sẽ hoạt động như cả hai trước, nhưng nó không có lỗi.

Hãy nhìn vào trang web cuộc gọi:

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

Biến fđược đưa ra làm đối số sẽ được sao chép vào tham số value. Nó sẽ không bao giờ thay đổi ngay cả khi changer()sẽ được gọi.

Bạn có thể muốn xem các tham số như một số loại biến cục bộ. Trên thực tế, chúng chủ yếu được xử lý như thế này trong mã máy được tạo.


Vì vậy, tại sao constđôi khi bạn nhìn thấy ? Bạn thấy nó nếu một con trỏ được định nghĩa là tham số.

Khi bạn không muốn thay đổi giá trị được chỉ định , bạn cần thêm const; nhưng làm điều đó ở vị trí chính xác!

void effective(int const * pointer);

void futile(int * const pointer);

void possible_but_overly_restricted(int const * const pointer);

Câu hỏi là về các nguyên mẫu mặc dù, nguyên mẫu float fabsf( float const );không liên quan gì đến việc thực hiện chức năng (không phải lặp lại const), trên thực tế, constnó bị bỏ qua hoàn toàn trong nguyên mẫu
MM

2
Có thể const trong định nghĩa hàm mà không đi trong nguyên mẫu?
dùng24205

3
@ user24205 có thể
Daniel Jour

33

C sử dụng pass theo giá trị. Giá trị cho tham số của hàm là một bản sao của đối số bạn đưa ra.

Bạn có thể sao chép cả float và non-const, và kết quả là float không const.

Nó tương tự như bài tập:

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

Trong thực tế, ngôn ngữ chỉ định rằng giá trị của một biểu thức không bao giờ có thể là const, tức là khi một giá trị được đọc từ một biến, giá trị đó constthậm chí không phải là nếu biến đó là.


8

Bởi vì ngôn ngữ C sử dụng vượt qua theo ngữ nghĩa giá trị, bất kỳ đối số nào bạn chuyển đến nó, trong khi nó có thể được sửa đổi trong nội bộ, không ảnh hưởng trực tiếp đến giá trị bạn truyền vào.

Điều này có nghĩa là từ quan điểm của người gọi, float fabsf( float );float fabsf( const float );giống nhau. Vì vậy, không có điểm nào trong việc đưa ra tham số const.

Trường hợp ý nghĩa để sử dụng constlà nếu tham số bạn truyền vào là một con trỏ, ví dụ:

void print_string(char *str)

Hàm này, mặc dù tên cho thấy, có thể hủy bỏ con trỏ đã cho và sửa đổi những gì nó trỏ, nghĩa là str[0] = 'x', dẫn đến thay đổi có thể xem được bởi hàm gọi. Nếu chức năng này được định nghĩa như thế này:

void print_string(const char *str)

Người gọi được đảm bảo rằng chức năng không thể thực hiện bất kỳ sửa đổi nào đối với những strđiểm nào.


"Người gọi được đảm bảo rằng chức năng không thể thực hiện bất kỳ sửa đổi nào ..." là không đúng. Hàm biết địa chỉ của dữ liệu và do đó có thể sửa đổi nó, ví dụ : ((char*)str)[0] = 'f'. Do đó, const ... *trong danh sách đối số chỉ là "tuyên bố ý định".
oromoiluig

5

Để thêm một quan điểm luật sư ngôn ngữ:

Để hai loại chức năng tương thích, cả hai sẽ chỉ định loại trả về tương thích. Ngoài ra, các danh sách loại tham số, nếu cả hai đều có mặt, sẽ đồng ý về số lượng tham số và sử dụng dấu kết thúc dấu chấm lửng; tham số tương ứng sẽ có loại tương thích . [..] Trong việc xác định khả năng tương thích loại và loại tổng hợp, [..] mỗi tham số được khai báo với loại đủ điều kiện được coi là có phiên bản không đủ tiêu chuẩn của loại khai báo .

N1570 6.7.6.3/15

Điều đó có nghĩa là hai cái này tương thích:

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

Do đó, bạn có thể viết nguyên mẫu có hoặc không const(có nghĩa là không có ý nghĩa hơn; ít gõ / đọc) và có thể thêm constvào định nghĩa hàm nếu bạn muốn tránh vô tình sửa đổi tham số (sao chép - gọi theo giá trị!) Bên trong các hàm thân hình.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.