2015-10-24 13 views
14

Trường hợp 1:Tại sao không có lỗi khi chuyển đối số dòng lệnh khi khai báo chính là `int main (void)`?

void hello(void) { 
    //something 
} 

int main() 
{ 
    hello(1); //error 
    return 0; 
} 

Trường hợp 2:

int main(void) { 
    //something 
    return 0; 
} 

Thực hiện:

./a.out something something //No error, Why? 

Tại sao không có lỗi? main sẽ không thể thực hiện bất kỳ đối số nào. Vậy tại sao có thể cung cấp các đối số từ dòng lệnh?

+0

Tại sao bạn lại gặp lỗi? –

+0

@OliverCharlesworth Bởi vì chúng tôi đang chuyển đối số cho chính? trình biên dịch không đi vào hình ảnh nhưng tại thời gian chạy/loadtime tại sao không có lỗi? – JagsVG

+2

Shell * luôn luôn * gửi các đối số của nó tới chương trình - ngay cả khi bạn không cung cấp (thường là nó gửi 'argv [0]'). 'main' không phải là cùng một loại hàm như' hello'. – usr2564301

Trả lời

14

Vì trình biên dịch C và trình thông dịch dòng lệnh (hoặc bất kỳ thứ gì được sử dụng để gọi chương trình của bạn) là những thứ khác nhau.

Ngôn ngữ C cho phép nhiều cách khác nhau cách khai báo chính().

Trình thông dịch dòng lệnh sẽ thực hiện bất kỳ đối số nào có sẵn cho chương trình. Nếu chương trình bỏ qua chúng, đó không phải là việc của nó.

Trình thông dịch dòng lệnh thậm chí không biết rằng bạn đã sử dụng C để biên dịch chương trình của bạn. Trên máy tính của tôi, chương trình có thể được viết bằng C, C++, Mục tiêu-C, Mục tiêu-C++, Swift, Fortran, Ada, v.v. Mỗi trình biên dịch này có thể hoặc không thể làm việc để chấp nhận các lệnh từ dòng lệnh.

9

Không kiểm tra đặc tả cũng như kết quả được biên dịch, nó sẽ không gây ra lỗi vì thời gian chạy C sẽ nhận đối số và chuyển chúng đến main(), nhưng loại này main() sẽ bỏ qua các đối số đã qua và nếu đó là nhiệm vụ của người gọi lên bộ nhớ (stack) được sử dụng như các đối số, nó sẽ gây ra không có vấn đề chỉ là nhận được một số đối số và không sử dụng chúng trong mã.

Mã này sẽ không phát ra lỗi trong C:

void hello(); // in C, the compiler won't check arguments 

int main() { 
    hello(1); //no error 
    return 0; 
} 

void hello(void) { 
    //something 
} 
+0

Tôi không bao giờ biết rằng 'void hello();' sẽ hoạt động khác với 'void hello (void);' Thú vị. Và tôi đã học được C vào năm 1989. Oh well. –

+0

Tôi nghĩ rằng bạn tạo ra một điểm tuyệt vời ở đây, nhưng nó là loại ẩn đi: "các 'đối số' của' main' * không cần dọn dẹp ngăn xếp * ". Đúng không? (Cả hai có nghĩa là như thế nào tôi đọc nó từ câu trả lời của bạn và, tốt, thực tế.) – usr2564301

+3

@Jongware Các đối số được truyền cho 'main' được làm sạch khỏi ngăn xếp theo hàm * gọi *' main', là một shim được cung cấp bởi thư viện C và hàm đó không biết hoặc quan tâm cách 'main' được khai báo. Điều này không đặc biệt đối với 'main'; đây là quy ước gọi điện thông thường của C cho tất cả các chức năng. (Các phần mở rộng của trình biên dịch như '__stdcall' có thể thay đổi quy ước. Những điều xấu sẽ xảy ra nếu bạn áp dụng chúng vào' main' - hoặc tới bất kỳ hàm nào khác được gọi bởi thư viện C.) – zwol

5

./a.out something something không trực tiếp gọi hàm chính của bạn. Hàm main được gọi bởi thư viện runtime c. Các đối số dòng lệnh được đặt trong một vùng ở đâu đó trên ngăn xếp (rất bắt đầu) bởi thời gian chạy bộ nạp/c. Đó là tối đa bạn nếu bạn muốn truy cập các đối số này hay không.

Plus như được chỉ ra trong một trong các nhận xét cũng như ít nhất một đối số dòng lệnh luôn luôn được chuyển anyways (tên của chương trình ./a.out chính xác) - vì vậy bạn phải tự hỏi về lỗi trong trường hợp đó .

2

Khi bạn biên dịch chương trình của mình bằng cách sử dụng gcc program_name.c, trình biên dịch sẽ báo cáo mọi cảnh báo hoặc lỗi thời gian có thể biên dịch có thể xảy ra. Vì các đối số dòng lệnh không được truyền vào thời gian biên dịch, trình biên dịch không biết về nó và chương trình chỉ bỏ qua các đối số đó.

Trong trường hợp hello, trình biên dịch biết nguyên mẫu của hàm này và hy vọng không có tham số nào được chuyển trong cuộc gọi và do đó báo cáo lỗi trong trường hợp bất kỳ đối số nào được truyền cho nó.

+0

@Down cử tri; Một bình luận sẽ được đánh giá cao? – haccks

3

Hãy nhớ rằng ISO C chỉ định hai chữ ký có thể có của main: int main(void)int main(int, char *[]) và các phiên bản tương đương của chúng, như int main(int, char **) do phân rã từ điểm đến con trỏ.Chi tiết này được trình bày chi tiết hơn here.

Câu hỏi này có thể được trả lời bằng cách xem xét câu hỏi ngược lại: thời gian chạy C biết điều gì main để gọi? C không có độ phân giải quá tải! Điều này được giải thích here. Một thời gian ngắn, những người khác được đẩy nhưng không được truy cập vì không có dấu hiệu từ C để làm điều đó.

Các vấn đề liên quan