2013-05-06 52 views
12

Tôi đã mua cuốn sách này có tên là "Viết mã rắn".Giới thiệu về "NULL" trong mã cụ thể này

Trong chương đầu tiên, có mã này:

while(*pchTo++ = *pchFrom++) 
    NULL; 

tôi thực sự không có được những gì mà NULL làm trong vòng lặp đó.

+1

Nó tách dấu chấm phẩy khỏi điều kiện vòng lặp. (Đó là mã số chết.) –

+21

Và một cuốn sách như vậy được gọi là "Viết Mã Rắn"? – duDE

+11

Cho dù thực hành như vậy là mong muốn được mở để tranh luận, nhưng một cuốn sách sử dụng một cấu trúc như vậy mà không dành ít nhất một đoạn ngắn để giải thích động lực tấn công tôi như không phải là một cuốn sách hay ... –

Trả lời

3

Vòng lặp đó sao chép một chuỗi. Các NULL là chỉ có để cung cấp một cơ thể vòng lặp.

+2

Điều đó thật khó hiểu ... đặc biệt là đối với sách tham khảo. Anh ta có thể chỉ đơn giản là rời khỏi cơ thể trong khi trống rỗng với hai dấu ngoặc nhọn: 'while (...) {}'. Hoặc thậm chí làm điều thực sự: 'while (* pchFrom) {* pchTo ++ = * pchFrom ++; } '. Đây là cách rõ ràng hơn .. – Gui13

+1

@ xgbi: Điều đó không sao chép null terminator. – Joren

+0

Wooops, tôi sẽ để người đọc khắc phục vấn đề này ... – Gui13

6

Tác giả có thể viết một while vòng lặp hoàn toàn trống rỗng giống như bạn có thể viết một cơ thể ít for vòng lặp. Điều đó sẽ trông giống như:

while (*pchTo++ = *pchFrom++); 

/* or */ 

while (*pchTo++ = *pchFrom++) 
    ; 

Cả hai điều này có thể gây nhầm lẫn cho một số người để họ thêm NULL để cung cấp cho cơ thể và làm cho nó ít khó hiểu.

Sửa

Lưu ý bạn có thể làm tương tự với một vòng lặp for:

for (head = list->head; head->next; head = head->next); 
/* or */ 
for (head = list->head; head->next; head = head->next) 
    ; 
/* or */ 
for (head = list->head; head->next; head = head->next) 
    NULL; 

Và tất cả những gì sẽ làm là đi qua một danh sách bằng cách vào phần tử tiếp theo trong khi phần tử tiếp theo không phải là NULL

+3

Tôi không thấy làm thế nào đó là "ít khó hiểu".Có một biểu thức có giá trị không được sử dụng và không có tác dụng phụ có vẻ khó hiểu hơn nhiều. Bằng chứng của tôi? Thực tế là OP phải đặt câu hỏi này. –

+0

Nó ít gây nhầm lẫn cho những người mong đợi một cơ thể và chưa bao giờ nhìn thấy một vòng lặp mà không có một, hoặc ít nhất tôi đoán đó là lý do tại sao 'NULL' được đặt ở đó. Nó thực sự trông xấu xí với tôi và khi tôi có một đối tượng danh sách (như trên) không có thành viên 'tail', tôi thường có một chức năng tiện lợi sử dụng vòng lặp mà tôi đã trình bày ở trên chỉ để lấy nó. Trên một lưu ý biên tập: những người không bao gồm một thành viên 'đuôi' trong cấu trúc của họ thực sự nên xem xét lại thiết kế của họ. –

+0

Bất cứ ai (cố ý) đặt một ';' trong cùng một dòng với câu lệnh 'for' hoặc' while' xứng đáng (ít nhất) một cái còng vững chắc trên đầu. [Câu trả lời của Keith] (http://stackoverflow.com/a/16401457/1711796) một thời gian ngắn chạm vào sự nhầm lẫn có thể xảy ra. Trên một lưu ý phụ, một tùy chọn khác mà nhiều người thích sử dụng dấu ngoặc nhọn ('{}') ở dạng này hay dạng khác. – Dukeling

2

Cấu trúc này cung cấp một cách hay để đặt điểm ngắt khi làm việc với trình gỡ lỗi. Một số IDE không cho phép tôi đặt điểm ngắt trên vòng lặp và tôi đã có vòng lặp với các thân trống. Nếu bạn có một câu lệnh trong thân vòng lặp của bạn, thì dễ dàng hơn để đặt một điểm ngắt trên nó, ngay cả khi câu lệnh đó là vô dụng.

Nếu không, như nó đã được nói, nó phải làm chính xác cùng một điều hơn một cơ thể với một cơ thể trống rỗng.

3

Nó có khả năng truyền cảm hứng bởi cú pháp của lệnh rỗng Ada:

while condition loop 
    null; 
end loop; 

Ada sử dụng từ khóa null cho cả con trỏ hằng vô cho lệnh rỗng (và một vài thứ khác).

Nó có một số ưu điểm so với câu lệnh null của C, đó chỉ là dấu chấm phẩy. Đặc biệt, nó rõ ràng hơn nhiều. Một lỗi khá phổ biến trong mã C là để chèn một lệnh rỗng ngẫu nhiên bằng cách thêm một dấu chấm phẩy, đặc biệt đối với các lập trình viên C thiếu kinh nghiệm đã chưa làm việc ra nơi mà dấu chấm phẩy là cần thiết và nơi họ không phải là:

while (condition); 
{ 
    /* statements */ 
} 

Without dấu chấm phẩy, các câu lệnh được điều khiển bởi vòng lặp while. Với nó, phần thân của vòng lặp while trống và vòng lặp có thể là vô hạn nếu điều kiện không có tác dụng phụ.

Mặt khác, nếu bạn thực sự muốn có một câu lệnh rỗng, chỉ sử dụng dấu chấm phẩy có thể khiến người đọc tự hỏi nếu có điều gì đó vô tình bị bỏ quên.

Trong C, NULL là macro mở rộng đến hằng số con trỏ null được xác định thực hiện.Tác giả đang sử dụng nó ở đây:

while(*pchTo++ = *pchFrom++) 
    NULL; 

như một loại lệnh rỗng - đó thực sự hoạt động, bởi vì một biểu thức tiếp theo là một dấu chấm phẩy là một biểu tuyên bố trong đó báo cáo kết quả được đánh giá cho tác dụng phụ của nó. Vì nó không có tác dụng phụ, nó không làm gì cả; nó hoạt động giống như một tuyên bố vô thực:

while(*pchTo++ = *pchFrom++) 
    ; 

Một hình thức tương đương:

while(*pchTo++ = *pchFrom++) 
    42; 

Theo tôi, đây là cũng có ý định nhưng một ý tưởng tồi. Nó dễ dàng nhận ra đối với những người trong số chúng ta đã quen thuộc với cả C và Ada, nhưng hầu hết các lập trình viên có kinh nghiệm C sẽ nhìn vào nó và tự hỏi cái gì mà hằng số null null đang làm ở đó.

Nó không phải khá tệ như định nghĩa một tập hợp các macro để làm cho C nhìn như cú pháp của ngôn ngữ khác:

#define IF if (
#define THEN) 
#define BEGIN { 
#define END } 
#define ELSE } else { 

nhưng đó là theo tinh thần như vậy.

Lời khuyên của tôi: Đừng làm điều này. Nếu bạn muốn mã C của bạn có thể dễ dàng hiểu được bởi những độc giả biết C, hãy viết mã C thành ngữ; không phát minh ra các thủ thuật thông minh để làm cho nó trông giống như một cái gì đó khác. Null tuyên bố có thể gây nhầm lẫn, dẫn người đọc tự hỏi nếu một cái gì đó đã được bỏ ra vô tình. Giải pháp tốt nhất, IMHO, là sử dụng nhận xét:

while(*pchTo++ = *pchFrom++) { 
    /* empty body */ 
} 
+1

Tôi tìm thấy 'while (* pchTo ++ = * pchFrom ++) {}' rõ ràng không kém. Khối trống rỗng mà không có không gian để đặt một cái gì đó có tín hiệu "không làm gì" là cố ý. –

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