ทำไมฟังก์ชั่นค่าสัมบูรณ์ใน C ไม่ยอมรับอินพุต const?


23

ใน C ต้นแบบสำหรับฟังก์ชันค่าสัมบูรณ์ (ที่ยอมรับการลอย) คือ

 float fabsf( float );

ทำไมต้นแบบนี้จึงไม่ยอมรับค่าคงที่เช่นนี้

 float fabsf( float const );

fabsf จะไม่เปลี่ยนค่าของอินพุตหรือไม่

หากฉันมีฟังก์ชั่นที่รับอินพุตและเรียกใช้ fabsf ฉันต้องบังคับให้หลีกเลี่ยงการระบุอินพุตเป็น const หรือไม่

วิธีที่เหมาะสมในการจัดการกับความถูกต้อง const ในสถานการณ์นี้คืออะไร?


26
constซ้ำซ้อนที่นี่คุณคิดว่าเกิดอะไรขึ้น
MM

1
@MM ฉันคาดหวังว่ามันจะสร้างข้อผิดพลาดเวลารวบรวมถ้าฉันพยายามเปลี่ยนค่าของอินพุตภายในฟังก์ชั่น สิ่งนี้ไม่ถูกต้องหรือ
user24205

16
เนื่องจากพารามิเตอร์ภายในฟังก์ชั่นเป็นสำเนาในเครื่องการเพิ่มconstจึงไม่มีความหมายอย่างสมบูรณ์
Lundin

1
" fabsf จะไม่เปลี่ยนค่าของอินพุตจะเป็นอย่างไร " คุณจะบอกได้อย่างไร พารามิเตอร์ถูกส่งผ่านตามค่า
David Schwartz

รหัสต่อไปนี้เป็นกฎหมาย C: float const x = -1.0; float y = fabsf(x);ดังนั้นจึงดูเหมือนว่าผมว่าfabsf ไม่ยอมรับปัจจัยการผลิต const ไม่มีทางที่จะพูดว่า "คุณสามารถส่งต่อฉันfloatตามมูลค่า แต่คุณไม่สามารถผ่านconst floatได้" (และอย่างที่เราเห็นในคำตอบ C ไม่ได้ให้วิธีที่ต้องการให้อินพุตของฟังก์ชั่นเป็น a float const.)
David K

คำตอบ:


14

แก้ไข

ในฐานะที่เป็น MM แสดงความคิดเห็นกับพารามิเตอร์ในต้นแบบที่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;
}

ไม่มีข้อความแสดงข้อผิดพลาด

อย่างไรก็ตามฉันจะปล่อยต้นฉบับไว้ด้วยความหวังว่ามันจะช่วยได้


เป็นต้นฉบับ

constที่พารามิเตอร์นี้จะทำให้พารามิเตอร์อ่านอย่างเดียวภายในฟังก์ชั่น

ตัวอย่างเช่น:

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 ใช่มันสามารถ
Daniel Jour

33

C ใช้ pass by value ค่าสำหรับพารามิเตอร์ของฟังก์ชันคือสำเนาของอาร์กิวเมนต์ที่คุณให้

มันก็โอเคที่จะคัดลอกทั้ง const และ non-const ลอยและผลที่ได้คือไม่ใช่ลอย const

มันคล้ายกับการมอบหมาย:

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ชี้ไป


"ผู้โทรมั่นใจได้ว่าฟังก์ชั่นไม่สามารถทำการแก้ไขใด ๆ ... " ไม่เป็นความจริง ฟังก์ชั่นรู้ที่อยู่ของข้อมูลและสามารถปรับเปลี่ยนได้ด้วยเช่น: ((char*)str)[0] = 'f'. const ... *ในรายการข้อโต้แย้งจึงเป็นเพียง "การประกาศเจตนา"
oromoiluig

5

วิธีเพิ่มมุมมองทนายภาษา:

สำหรับฟังก์ชั่นสองประเภทที่เข้ากันได้ทั้งสองจะต้องระบุประเภทการคืนที่เข้ากัน ยิ่งกว่านั้นรายการประเภทพารามิเตอร์หากมีทั้งคู่จะต้องยอมรับในจำนวนพารามิเตอร์และการใช้งานของจุดไข่ปลารูปไข่; พารามิเตอร์ที่เกี่ยวข้องจะต้องมีประเภทที่เข้ากันได้ [ .. ] ในการกำหนดประเภทและความเข้ากันได้ของรูปแบบคอมโพสิต [ .. ] แต่ละพารามิเตอร์ประกาศด้วยชนิดที่มีคุณสมบัติเหมาะสมจะมาเป็นมีรุ่นที่ไม่เหมาะสมของประเภทของประกาศ

N1570 6.7.6.3/15

นั่นหมายความว่าทั้งสองเข้ากันได้:

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

ดังนั้นคุณสามารถเขียนต้นแบบที่มีหรือไม่มีconst(ซึ่งหมายความว่าไม่มีความหมายมากขึ้นพิมพ์ / อ่านน้อยลง) และสามารถเพิ่มconstคำจำกัดความของฟังก์ชันได้หากคุณต้องการหลีกเลี่ยงการแก้ไขพารามิเตอร์ (คัดลอก - โทรตามค่า!) โดยไม่ตั้งใจ ร่างกาย.

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.