2010-01-18 105 views
48

Tôi đã nhận thấy trong một số trường hợp khi tái cấu trúc các phần khác nhau của mã C và C++, dấu phẩy được sử dụng thay vì dấu chấm phẩy để phân tách . Một cái gì đó như thế này;Ảnh hưởng của việc sử dụng dấu phẩy thay vì dấu chấm phẩy trong C và C++

int a = 0, b = 0; 
a = 5, b = 5; 

Nơi tôi dự kiến ​​sẽ có

int a = 0, b = 0; 
a = 5; b = 5; 

Tôi biết rằng C và C++ cho phép sử dụng dấu phẩy để phân cách báo cáo (đặc biệt là tiêu đề loop), nhưng sự khác biệt là những gì nếu có giữa hai miếng này của mã? Tôi đoán là dấu phẩy đã được để lại trong kết quả của việc cắt dán &, nhưng nó có phải là một lỗi và nó có thực thi hiệu quả không?

+8

Đáng nói rằng "toán tử dấu phẩy" trong dòng thứ hai khác ngữ nghĩa với dấu phẩy phân định các biểu thức khởi tạo trong 'int a = 0, b = 0;'. –

+1

Cũng có vấn đề này với toán tử dấu phẩy trong đó 'int * a, b;' không giống như 'int * a; int * b; ' – JPvdMerwe

+2

Đó là lý do tại sao tôi luôn đặt con trỏ/bộ sửa đổi tham chiếu bên cạnh biến, không phải kiểu. 'int * a, b;' – mskfisher

Trả lời

74

Nó không tạo sự khác biệt trong các mã bạn được đăng. Nói chung, dấu phẩy phân tách các biểu thức giống như dấu chấm phẩy, tuy nhiên, nếu bạn lấy toàn bộ làm biểu thức, thì toán tử dấu phẩy có nghĩa là biểu thức sẽ đánh giá đối số cuối cùng.

Dưới đây là một ví dụ:

b = (3,5); 

sẽ đánh giá 3, sau đó 5 và gán sau này để b. Vì vậy, b == 5. Lưu ý rằng các dấu ngoặc rất quan trọng ở đây:

b = 3, 5; 

sẽ đánh giá b = 3, sau đó 5 và kết quả của toàn bộ biểu thức là 5, tuy nhiên b == 3.

Nhà điều hành dấu phẩy là đặc biệt hữu ích trong việc cho các vòng lặp khi mã lặp của bạn không phải là một i ++ đơn giản, nhưng bạn cần thực hiện nhiều lệnh. Trong trường hợp đó, dấu chấm phẩy không hoạt động tốt với cú pháp vòng lặp.

+8

+1: để 'đánh giá thành đối số cuối cùng.' – jldupont

+1

+1, giải thích tốt. Chỉ muốn thêm một lỗ hổng phổ biến có thể hữu ích nếu bạn đang xử lý nhiều thứ sau: gõ 'a [j, k]' thay vì 'a [j] [k]' thường dẫn đến kết quả không mong muốn. – laura

+0

Vâng, về mặt kỹ thuật, dấu phẩy là toán tử nhị phân, vì vậy nó chỉ có biểu thức trái và phải. Nhưng khi nhiều dấu phẩy được sử dụng ở cùng một mức, kết quả đệ quy thực sự là nó được đánh giá đến biểu thức cuối cùng. – x4u

20

Dấu phẩy là toán tử trả về giá trị luôn là đối số thứ 2 (phải) trong khi dấu chấm phẩy chỉ kết thúc câu lệnh. Điều đó cho phép toán tử dấu phẩy được sử dụng bên trong các câu lệnh khác hoặc ghép nối nhiều câu lệnh để xuất hiện dưới dạng một.

Ở đây hàm f (x) được gọi và sau đó x > y được đánh giá cho câu lệnh if.

if(y = f(x), x > y) 

Một ví dụ khi nó được sử dụng chỉ để tránh một sự cần thiết của khối

if(...) 
    x = 2, y = 3; 

if(...) { 
    x = 2; 
    y = 3; 
} 
2

một cách sử dụng sẽ là trong mã chơi golf:

if(x==1)y=2,z=3; 
if(x==1){y=2;z=3;} 

dòng đầu tiên là ngắn hơn, nhưng điều đó có vẻ quá khó hiểu để sử dụng trong sự phát triển bình thường

+3

... và bất cứ ai viết mã như thế, sẽ sớm nhận được những gì họ xứng đáng. –

+0

Để nhấn mạnh hiệu ứng của dấu phẩy so với dấu chấm phẩy, dòng thứ hai của bạn có lẽ nên sử dụng dấu chấm phẩy giữa y và z, như trong '{y = 2; z = 3;}' – mskfisher

+0

@mskfisher: cảm ơn vì đã chú ý, tôi đã nhập sai ví dụ thứ hai – catwalk

5

Nhà điều hành dấu phẩy đánh giá tất cả toán hạng từ trái sang phải, và kết quả là giá trị của toán hạng cuối cùng.

Điều này chủ yếu hữu ích trong các vòng lặp nếu bạn muốn thực hiện nhiều tác vụ trong phần "gia tăng", e.g (lùi một chuỗi)

for (int lower = 0, upper = s.size() - 1; lower < upper; ++lower, --upper) 
    std::swap(s[lower], s[upper]); 

Một ví dụ khác, nơi mà nó có thể là một lựa chọn (tìm tất cả các lần xuất hiện trong một chuỗi):

#include <string> 
#include <iostream> 

int main() 
{ 
    std::string s("abracadabra"); 
    size_t search_position = 0; 
    size_t position = 0; 

    while (position = s.find('a', search_position), position != std::string::npos) { 
     std::cout << position << '\n'; 
     search_position = position + 1; 
    } 
} 

Đặc biệt, logic không thể được sử dụng cho điều này điều kiện, vì cả số không và không có nghĩa là ký tự được tìm thấy trong chuỗi. Với dấu phẩy, mặt khác, position = s.find() được gọi mỗi khi điều kiện được đánh giá, nhưng kết quả của phần này của điều kiện này chỉ bị bỏ qua.

Đương nhiên có những cách khác để viết vòng lặp:

while ((position = s.find('a', search_position)) != std::string::npos) 

hoặc chỉ

while (true) { 
    position = s.find('a', search_position); 
    if (position == std::string::npos) 
     break; 
    ... 
} 
2

Như Frank mentioned, làm thế nào các nhà điều hành dấu phẩy được sử dụng trong ví dụ của bạn không gây ra một lỗi. Các nhà điều hành dấu phẩy thể gây nhầm lẫn vì nhiều lý do:

  • nó không nhìn thấy quá thường xuyên bởi vì nó chỉ cần thiết trong một số tình huống đặc biệt
  • có một số sử dụng cú pháp khác của dấu phẩy có thể trông giống như một nhà điều hành dấu phẩy - nhưng chúng không phải là (dấu phẩy được sử dụng để phân tách các tham số/đối số chức năng, các dấu phẩy được sử dụng để tách các khai báo hoặc các biến khởi tạo)

Vì nó khó hiểu và thường không cần thiết, nên tránh toán tử dấu phẩy trừ một số tình huống rất cụ thể :

  • nó có thể hữu ích để thực hiện nhiều hoạt động trong một hoặc nhiều biểu thức kiểm soát một tuyên bố for của
  • nó có thể được sử dụng trong các macro tiền xử lý để đánh giá nhiều hơn một biểu trong một tuyên bố duy nhất. Điều này thường được thực hiện để cho phép một macro thực hiện nhiều thứ và vẫn là một biểu thức duy nhất để macro sẽ 'vừa' ở những nơi chỉ cho phép biểu thức.

Toán tử dấu phẩy là một toán tử hackish khá nhiều theo định nghĩa - đó là hack trong 2 thứ chỉ được phép. Nó gần như luôn luôn xấu xí, nhưng đôi khi đó là tất cả những gì bạn có. Và đó là lần duy nhất bạn nên sử dụng nó - nếu bạn có tùy chọn khác, không sử dụng toán tử dấu phẩy. Tôi không thể nghĩ ra quá nhiều lý do khác để sử dụng toán tử, vì bạn có thể có được hiệu ứng tương tự bằng cách đánh giá các biểu thức trong các câu lệnh riêng biệt trong hầu hết các tình huống khác (mặc dù tôi chắc chắn rằng ai đó sẽ bình luận về việc sử dụng khác mà tôi đã bỏ qua).

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