2017-12-12 92 views
21

Trong khi nhìn vào một số mã C++ 03, tôi tìm thấy một thể hiện của các phân tích cú pháp gây nhiều tranh cãi nhất rằng nhầm lẫn tôi:phân tích cú pháp gây nhiều tranh cãi nhất với truy cập mảng

#include <sstream> 
#include <string> 

int main(int, char** argv) 
{ 
    std::stringstream ss(std::string(argv[0])); 
} 

live example on wandbox

Trong đoạn trên , ss là khai báo hàm có số std::string* và trả về std::stringstream.

Làm thế nào là std::string(argv[0]) được phân tích cú pháp là std::string*?

Trực giác Tôi nghĩ rằng argv[0] là truy cập rõ ràng vào argv.

+0

này thất bại trong việc biên dịch cho tôi với Visual Studio 2015 vì 'argv [0] 'rõ ràng là một 0 kích thước mảng kiểu' argv'. Tôi có thể nhận được kết quả tương tự như bạn nếu tôi sử dụng 'argv [1]'. Câu hỏi thú vị. –

+4

Tôi nghĩ rằng nó tương đương với 'std :: stringstream ss (std :: string argv []);' đó là chính nó tương đương với 'std :: stringstream ss (std :: string * argv);'. –

+0

Tôi nghĩ rằng có một hướng dẫn này, _if nó trông giống như một tuyên bố nó là one_. Vì vậy, như @ FrançoisAndrieux đã viết instantiation của bạn từ std :: string không phải là một instantiation nhưng thay vì một tuyên bố cho mảng của std: strings – ExOfDe

Trả lời

18

Lý do là bởi vì trong bối cảnh của một khai báo hàm, trình biên dịch sẽ giải thích std::string(argv[0]) như std::string argv[0], tức là một tuyên bố của một mảng không có kích thước như các tham số chức năng tênargv (làm lu mờ các argv từ main, vì đây là phạm vi khác), sau đó tương đương với một con trỏ theo số mảng-to-con trỏ-phân rã.

Do đó, std::stringstream ss(std::string(argv[0])); nghĩa giống như std::stringstream ss(std::string* argv);

Edit: Vì nó đã annotaded một cách chính xác trong các ý kiến, tờ khai mảng zero-kích thước không hợp lệ trong C++, làm cho chương trình vô hình thành. Khi biên dịch mã này với -pedantic cờ (GCC và clang), cảnh báo sẽ được phát hành. Visual Studio thậm chí còn tạo ra một lỗi biên dịch. Đối với bất kỳ chỉ mục mảng nào khác là 0, thì đối số trên vẫn giữ nguyên.

+1

do đó, phân tích cú pháp khó chịu nhất thậm chí còn ác hơn tôi luôn nghĩ ...nó không chỉ là "nếu nó trông giống như một khai báo hàm nó là khai báo hàm" nhưng cũng "nếu nó trông giống như khai báo hàm không hợp lệ thì nó là khai báo hàm" .... omfg – user463035818

+2

@ tobi303: Xem qua ngữ pháp . Nó định nghĩa các mảng gần như 'type name_optional [size_expression]', và không có quy tắc ngữ pháp đặc biệt nào cho các biểu thức đánh giá bằng không. Sẽ là _very_ cứng, mặc dù, như đánh giá biểu hiện trong C + + là Turing-hoàn thành. – MSalters

+1

@ tobi303 nó không phải là một tuyên bố không hợp lệ, mặc dù. Trong C++, [một khai báo biến được phép bọc tên biến trong dấu ngoặc đơn] (https://stackoverflow.com/questions/29675601/). Tức là 'int (x)' giống với 'int x'. Đây là lý do tại sao 'std :: string (argv [0])' có thể được xem như 'std :: string argv [0]' trong ngữ cảnh này. Chỉ cần loại bỏ 'std :: string' để tránh MVP:' std :: stringstream ss (argv [0]); ' –

7

Tôi tin rằng điều này tuân theo nguyên tắc "cú pháp khai báo giống như cú pháp biểu thức" và thực tế là các tham số "mảng" là con trỏ.

Các tờ khai mảng sau là tương đương:

int x[1]; 
int (x)[1]; 
int (x[1]); 

nhiều hơn hoặc ít hơn vì x[a], (x)[a], và (x[a]) là những biểu hiện tương đương.

Như vậy,

std::stringstream ss(std::string(argv[0])) 

       <=> 

std::stringstream ss(std::string argv[0]) 

       <=> 

std::stringstream ss(std::string* argv) 
Các vấn đề liên quan