2012-07-19 68 views
5

Tôi vừa gặp lỗi khó chịu trong C++. Vì vậy, tôi đã có danh sách các thanh ghi và các giá trị, được bọc trong một cấu trúc và sau đó các cấu trúc đó được khởi tạo trong một mảng. Nhưng sau đó tôi vô tình nhập () thay vì {}. Dưới đây là một số mã kiểm tra:Ý nghĩa của dấu ngoặc đơn trong C++ và C

#include <stdio.h> 

struct reg_val { 
     unsigned reg; 
     unsigned val; 
}; 

struct reg_val faulty_array[] = { 
     {0x5001, 0xff}, 
     {0x5580, 0x01}, 
     (0x5580, 0x02), //<- THIS LINE IS THE PROBLEM 
     (0x5589, 0x00), //<- AND THIS LINE 
}; 

struct reg_val good_array[] = { 
     {0x5001, 0xff}, 
     {0x5580, 0x01}, 
     {0x5580, 0x02}, 
     {0x5589, 0x00}, 
}; 

int main() 
{ 
     unsigned i; 
     unsigned faulty_size = sizeof(faulty_array)/sizeof(struct reg_val); 
     printf("Size of faulty array: %d\n", faulty_size); 

     for (i = 0; i < faulty_size; ++i) { 
       printf("faulty reg: %x val: %x\n", faulty_array[i].reg, 
         faulty_array[i].val); 
     } 

     unsigned good_size = sizeof(good_array)/sizeof(struct reg_val); 
     printf("\nSize of good array: %d\n", good_size); 
     for (i = 0; i < good_size; ++i) { 
       printf("good reg: %x val: %x\n", good_array[i].reg, 
         good_array[i].val); 
     } 
     return 0; 
} 

Tôi quen thuộc hơn với C và tôi ngạc nhiên này vẫn được biên soạn với g ++:

$ g++ -Wall array.cc 
array.cc:11: warning: left-hand operand of comma has no effect 
array.cc:12: warning: left-hand operand of comma has no effect 
array.cc:13: warning: missing braces around initializer for ‘reg_val’ 
$ ./a.out 
Size of faulty array: 3 
faulty reg: 5001 val: ff 
faulty reg: 5580 val: 1 
faulty reg: 2 val: 0  <-- the first value gets discarded as mentioned in the compiler warning 

Size of good array: 4 
good reg: 5001 val: ff 
good reg: 5580 val: 1 
good reg: 5580 val: 2 
good reg: 5589 val: 0 

Mã này sẽ rõ ràng là thất bại trong việc biên dịch với một trình biên dịch C, những gì là khác biệt trong C + + mà làm cho một trình biên dịch C + + (mặc dù grudgingly) chấp nhận mã này?

Trả lời

4

Để trả lời câu hỏi của bạn, đầu tiên tôi sẽ trả lời: Tại sao điều này không biên dịch trong C? Vâng, đó là thất bại trong việc biên dịch do:

initializer element is not constant 

Đối với biện pháp tốt, chúng ta hãy thả {} s từ C:

struct reg_val faulty_array[] = { 
     {0x5001, 0xff}, 
     {0x5580, 0x01}, 
     0x5580, 0x02, //<- THIS LINE IS THE PROBLEM 
     0x5589, 0x00, //<- AND THIS LINE 
}; 

Bây giờ đầu ra chương trình:

Size of faulty array: 4 
faulty reg: 5001 val: ff 
faulty reg: 5580 val: 1 
faulty reg: 5580 val: 2 
faulty reg: 5589 val: 0 

Đây là một cách hoàn hảo được cho phép bởi tiêu chuẩn C (và C++). C (và C++) làm phẳng các dấu ngoặc để khởi tạo các phần tử của các cấu trúc (điều này sẽ quay trở lại). Mã của bạn không thành công trong C vì các đối tượng có thời lượng lưu trữ tĩnh phải được khởi tạo với các biểu thức không đổi hoặc với các trình khởi tạo tổng hợp chứa các biểu thức không đổi. C không xử lý (0x5580, 0x02) dưới dạng biểu thức không đổi.

này (không vui) biên dịch trong C++ vì C++ đối xử với các nhà điều hành dấu phẩy giữa hai biểu thức liên tục như một biểu thức hằng số, do đó, mã của bạn có nhiều như:

struct reg_val faulty_array[] = { 
     {0x5001, 0xff}, 
     {0x5580, 0x01}, 
     0x02, 
     0x00, 
}; 

... đó là, tất nhiên, cho phép .

struct reg_val faulty_array[] = { 
     {0x5001, 0xff}, 
     {0x5580, 0x01}, 
     {0x02, 0x00}, 
}; 
+0

Ah, cảm ơn bạn. Tôi hiểu rồi. Điều đó có ý nghĩa. Nhưng gcc dường như không phải là rất hạnh phúc về tôi "nẹp phẳng". '$ gcc -Wall array.c array.c: 13: warning: thiếu dấu ngoặc ôm quanh initializer' – Lucas

+0

' gcc' với '-Wall' cũng sẽ cảnh báo bạn về' if (c = something()) 'vì' gợi ý dấu ngoặc đơn xung quanh bài tập được sử dụng làm giá trị true'. Chỉ vì một cái gì đó được cho phép bởi ANSI C không có nghĩa là nó sẽ không tạo ra một cảnh báo. –

+0

bạn đúng, 'gcc -std = c89-biên dịch mảng array.c' không có cảnh báo. – Lucas

3

C++ có toán tử dấu phẩy đánh giá cả hai toán hạng của nó và trả về giá trị của toán hạng bên phải của nó, bỏ qua bên trái của nó. You can see it more clearly here.

Và C quá, rõ ràng =) (Cảm ơn, @BenVoigt)

+2

Câu hỏi đặt ra là "Sự khác biệt trong C++ (so với C) là gì?"Câu trả lời không phải là" toán tử dấu phẩy " –

+0

@BenVoigt: Tôi không biết C, tôi chỉ giải thích lý do nó biên dịch trong C++ và tôi cho rằng anh ta đã cố gắng biên dịch nó trong C và phần đó không thành công. – Ryan

+0

Và tôi giả sử C++ cố gắng đánh giá các biểu thức này tại thời gian biên dịch khi chúng có các toán hạng liên tục và C không giải thích được lỗi so với cảnh báo giữa C và C++ – antlersoft

4

gì làm cho bạn nghĩ rằng nó sẽ không biên dịch trong C?

C++: http://ideone.com/KLPh4 C: http://ideone.com/VYUbL

Chú ý đến lời cảnh báo của bạn. Tôi không thể nhấn mạnh điều này. Cảnh báo có để giúp bạn nắm bắt những sai lầm như thế này.

Vâng, thông báo lỗi trong C làm cho sự khác biệt hoàn toàn rõ ràng: C yêu cầu khởi tạo là hằng số, không phải biểu thức tùy ý. Nó làm cho không có ý nghĩa với tôi lý do tại sao những người không coi hằng, vì đây biên dịch tốt trong C:

+4

Nó không biên dịch trong C-land vì " yếu tố khởi tạo không phải là hằng số. "Nói cách khác:' (expr, expr) 'không phải là một biểu thức liên tục hoặc khởi tạo tổng hợp. –

+0

Ideone thất bại với' lỗi biên dịch' trên ví dụ C. – pmr

+0

@Travis: Cảm ơn, đã cập nhật câu trả lời –

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