การประกาศฟังก์ชั่นไม่ใช่ต้นแบบ


158

ฉันมีห้องสมุดที่ฉันสร้าง

mylib.c:

#include <mylib.h>
int
testlib() {
    printf("Hello world\n");
    return (0);
}

mylib.h:

#include <stdio.h>
extern int testlib();

ในโปรแกรมของฉันฉันพยายามเรียกใช้ฟังก์ชันไลบรารีนี้:

myprogram.c:

#include <mylib.h>

int
main (int argc, char *argv[]) {
    testlib();
    return (0);
}

เมื่อฉันพยายามรวบรวมโปรแกรมนี้ฉันได้รับข้อผิดพลาดต่อไปนี้:

ในไฟล์รวมจาก myprogram.c: 1
mylib.h: คำเตือน 2: การประกาศฟังก์ชั่นไม่ใช่ต้นแบบ

ฉันกำลังใช้: gcc (GCC) 3.4.5 20051201 (Red Hat 3.4.5-2)

คำถามของฉันคือวิธีที่เหมาะสมในการประกาศต้นแบบฟังก์ชั่นคืออะไร?


1
ลบ extern จากการประกาศใน mylib.h โดยเฉพาะถ้าคุณเขียนโปรแกรม C บริสุทธิ์การประกาศ extern นั้นไม่จำเป็น
Ryan Ahearn

คำตอบ:


333

ใน C int foo()และint foo(void)มีฟังก์ชั่นที่แตกต่างกัน int foo()ยอมรับจำนวนข้อโต้แย้งโดยพลการในขณะที่int foo(void)ยอมรับข้อโต้แย้งที่ 0 ใน C ++ พวกเขาหมายถึงสิ่งเดียวกัน ฉันขอแนะนำให้คุณใช้voidอย่างสม่ำเสมอเมื่อคุณไม่ได้มีข้อโต้แย้ง

ถ้าคุณมีตัวแปรa, extern int a;เป็นวิธีที่จะบอกคอมไพเลอร์ที่aเป็นสัญลักษณ์ที่อาจจะอยู่ในหน่วยการแปลที่แตกต่างกัน (C คอมไพเลอร์พูดสำหรับแฟ้มแหล่งที่มา) ไม่แก้ปัญหาได้จนกว่าจะถึงเวลาการเชื่อมโยง ในทางกลับกันสัญลักษณ์ที่เป็นชื่อฟังก์ชั่นจะได้รับการแก้ไขในเวลาลิงก์ ความหมายของตัวระบุคลาสหน่วยเก็บข้อมูลในฟังก์ชัน ( extern, static) มีผลกับการมองเห็นเท่านั้นและexternเป็นค่าเริ่มต้นดังนั้นจึงexternไม่จำเป็นจริง ๆ

ฉันขอแนะนำให้ลบexternมันเป็นสิ่งที่ไม่เกี่ยวข้องและมักจะถูกละเว้น


9
ใช้(void) ใน Cเพื่อระบุว่าฟังก์ชั่นไม่มีข้อโต้แย้ง ใน C ++ เฉพาะถ้าคุณจำเป็นต้องใช้รหัสของคุณเพื่อรวบรวมเป็นทั้ง C และ C ++ ()ใช้เพียง
Keith Thompson

49

คำตอบด่วน: เปลี่ยนint testlib()เป็นint testlib(void)เพื่อระบุว่าฟังก์ชั่นไม่มีข้อโต้แย้ง

ต้นแบบคือโดยความหมายการประกาศฟังก์ชั่นที่ระบุประเภท (s) ของอาร์กิวเมนต์ของฟังก์ชัน (s)

ประกาศฟังก์ชั่นที่ไม่ใช่ต้นแบบเช่น

int foo();

เป็นการประกาศแบบเก่าที่ไม่ได้ระบุจำนวนหรือประเภทของข้อโต้แย้ง (ก่อนมาตรฐาน 1989 ANSI C นี่เป็นประกาศประเภทฟังก์ชันเดียวที่มีในภาษา) คุณสามารถเรียกใช้ฟังก์ชันดังกล่าวด้วยจำนวนอาร์กิวเมนต์ที่กำหนดเองและคอมไพเลอร์ไม่จำเป็นต้องบ่น - แต่ถ้า การโทรไม่สอดคล้องกับคำจำกัดความโปรแกรมของคุณมีพฤติกรรมที่ไม่ได้กำหนด

สำหรับฟังก์ชั่นที่รับอาร์กิวเมนต์หนึ่งตัวขึ้นไปคุณสามารถระบุประเภทของแต่ละอาร์กิวเมนต์ในการประกาศ:

int bar(int x, double y);

ฟังก์ชั่นที่ไม่มีข้อโต้แย้งเป็นกรณีพิเศษ ในทางตรรกะวงเล็บว่างจะเป็นวิธีที่ดีในการระบุว่าอาร์กิวเมนต์ แต่มีการใช้ไวยากรณ์นั้นสำหรับการประกาศฟังก์ชันแบบเก่าดังนั้นคณะกรรมการ ANSI C จึงคิดค้นไวยากรณ์ใหม่โดยใช้voidคำหลัก:

int foo(void); /* foo takes no arguments */

ฟังก์ชั่นความหมาย (ซึ่งรวมถึงรหัสสำหรับสิ่งที่ฟังก์ชั่นที่ไม่จริง) นอกจากนี้ยังมีการประกาศ ในกรณีของคุณคุณมีสิ่งที่คล้ายกับ:

int testlib()
{
    /* code that implements testlib */
}

testlibนี้จะมีการประกาศที่ไม่ใช่แบบอย่างที่ดีสำหรับ ตามคำจำกัดความสิ่งนี้จะบอกคอมไพเลอร์ที่testlibไม่มีพารามิเตอร์ แต่เป็นการประกาศเพียงบอกคอมไพเลอร์ที่testlibใช้จำนวนและชนิดของอาร์กิวเมนต์ที่ไม่ระบุ แต่คงที่

ถ้าคุณเปลี่ยน()การ(void)ประกาศจะกลายเป็นแบบอย่างที่ดี

ข้อดีของต้นแบบคือถ้าคุณตั้งใจโทรtestlibด้วยอาร์กิวเมนต์หนึ่งตัวขึ้นไปคอมไพเลอร์จะวินิจฉัยข้อผิดพลาด

(C ++ มีกฎแตกต่างกันเล็กน้อย C ++ ไม่มีการประกาศฟังก์ชั่นแบบเก่าและวงเล็บว่างเปล่าโดยเฉพาะหมายความว่าฟังก์ชั่นไม่มีข้อโต้แย้ง C ++ รองรับ (void)ไวยากรณ์เพื่อความสอดคล้องกับ C แต่ถ้าคุณต้องการรหัสของคุณเพื่อรวบรวมทั้ง C และ C ++ คุณควรใช้()ใน C ++ และ(void)ไวยากรณ์ใน C)


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