Thụt lề #defines


99

Tôi biết rằng #definecác s, v.v. thường không bao giờ được thụt vào. Tại sao?

Tôi đang làm việc trong một số mã tại thời điểm này có một hỗn hợp khủng khiếp của #defines, #ifdefs, #elses, #endifs, v.v. Tất cả những thứ này thường được trộn lẫn với mã C bình thường. Việc không thụt lề của chữ #defines khiến chúng khó đọc. Và hỗn hợp của mã được thụt vào với các mã không được thụt #definevào là một cơn ác mộng.

Lợi ích của việc không thụt lề #defines là gì? Nó có khiến tôi trở thành một người xấu nếu tôi thụt vào trong chúng không? Điều này không đẹp hơn nhiều sao?

#ifdef SDCC
    #if DEBUGGING == 1
        #if defined (pic18f2480)
            #define FLASH_MEMORY_END 0x3DC0
        #elif defined (pic18f2580)
            #define FLASH_MEMORY_END 0x7DC0
        #else
            #error "Can't set  up flash memory end!"
        #endif
    #else
        #if defined (pic18f2480)
            #define FLASH_MEMORY_END 0x4000
        #elif defined (pic18f2580)
            #define FLASH_MEMORY_END 0x8000
        #else
            #error "Can't set  up flash memory end!"
        #endif
    #endif
#else
    #if DEBUGGING == 1
        #define FLASH_MEMORY_END 0x7DC0
    #else
        #define FLASH_MEMORY_END 0x8000
    #endif
#endif

Câu trả lời:


103

Bộ tiền xử lý Pre-ANSI C không cho phép khoảng trống giữa đầu dòng và ký tự "#"; "#" đứng đầu phải luôn được đặt trong cột đầu tiên.

Những trình biên dịch trước ANSI C không tồn tại ngày nay. Sử dụng kiểu đã từng (khoảng trắng trước "#" hoặc khoảng trắng giữa "#" và số nhận dạng) mà bạn thích.

http://www.delorie.com/gnu/docs/gcc/cpp_48.html


26

Như một số người đã nói, một số trình biên dịch Pre-ANSI yêu cầu # là ký tự đầu tiên trên dòng nhưng chúng không yêu cầu phải gắn chỉ thị de tiền xử lý vào nó, vì vậy thụt lề được thực hiện theo cách này.

#ifdef SDCC
#  if DEBUGGING == 1
#    if defined (pic18f2480)
#      define FLASH_MEMORY_END 0x3DC0
#    elif defined (pic18f2580)
#      define FLASH_MEMORY_END 0x7DC0
#    else
#      error "Can't set  up flash memory end!"
#    endif
#  else
#    if defined (pic18f2480)
#      define FLASH_MEMORY_END 0x4000
#    elif defined (pic18f2580)
#      define FLASH_MEMORY_END 0x8000
#    else
#      error "Can't set  up flash memory end!"
#    endif
#  endif
#else
#  if DEBUGGING == 1
#    define FLASH_MEMORY_END 0x7DC0
#  else
#    define FLASH_MEMORY_END 0x8000
#  endif
#endif

Tôi thường thấy kiểu này trong các tiêu đề Unix cũ nhưng tôi ghét nó vì việc tô màu cú pháp thường không thành công trên mã như vậy. Tôi sử dụng màu rất dễ nhìn thấy cho chỉ thị tiền xử lý để chúng nổi bật (chúng ở cấp độ meta nên không phải là một phần của dòng mã thông thường). Bạn thậm chí có thể thấy rằng SO không tô màu chuỗi theo cách hữu ích.


16

Về phân tích cú pháp của các chỉ thị tiền xử lý, tiêu chuẩn C99 (và tiêu chuẩn C89 trước đó) rõ ràng về trình tự các hoạt động được trình biên dịch thực hiện một cách hợp lý. Đặc biệt, tôi tin rằng nó có nghĩa là mã này:

/* */ # /* */ include /* */ <stdio.h> /* */

tương đương với:

#include <stdio.h>

Dù tốt hơn hay tệ hơn, GCC 3.4.4 với '-std = c89 -pedantic' chấp nhận dòng đầy bình luận, ở bất kỳ mức nào. Tôi không ủng hộ điều đó như một phong cách - không phải trong một giây (nó thật kinh khủng). Tôi chỉ nghĩ rằng nó là có thể.

ISO / IEC 9899: 1999 phần 5.1.1.2 Các giai đoạn dịch cho biết:

  1. [Lập bản đồ ký tự, bao gồm cả các đoạn]

  2. [Nối dòng - xóa dấu gạch chéo ngược dòng mới]

  3. Tệp nguồn được phân tách thành các mã thông báo tiền xử lý và chuỗi các ký tự khoảng trắng (bao gồm cả nhận xét). Tệp nguồn không được kết thúc bằng mã thông báo tiền xử lý một phần hoặc trong một phần nhận xét. Mỗi nhận xét được thay thế bằng một ký tự khoảng trắng. Các ký tự dòng mới được giữ lại. Việc mỗi chuỗi ký tự khoảng trắng không phải là ký tự trắng có được giữ lại hay thay thế bằng một ký tự khoảng trắng hay không là do việc triển khai xác định.

  4. Các chỉ thị tiền xử lý được thực thi, các lệnh gọi macro được mở rộng, […]

Phần 6.10 Các chỉ thị tiền xử lý cho biết:

Chỉ thị tiền xử lý bao gồm một chuỗi mã thông báo tiền xử lý bắt đầu bằng mã thông báo tiền xử lý # mà (ở đầu giai đoạn dịch 4) là ký tự đầu tiên trong tệp nguồn (tùy chọn sau khoảng trắng không chứa ký tự dòng mới) hoặc ký tự đó theo sau khoảng trắng chứa ít nhất một ký tự dòng mới và được kết thúc bằng ký tự dòng mới tiếp theo.

Tranh chấp duy nhất có thể xảy ra là biểu thức trong ngoặc đơn '(ở đầu giai đoạn dịch 4)', có thể có nghĩa là các nhận xét trước hàm băm phải vắng mặt vì chúng không được thay thế bằng dấu cách cho đến khi kết thúc giai đoạn 4.

Như những người khác đã lưu ý, các bộ tiền xử lý chuẩn C không hoạt động đồng nhất theo một số cách và khoảng trắng trước và trong các lệnh tiền xử lý là một trong những lĩnh vực mà các trình biên dịch khác nhau đã làm những việc khác nhau, bao gồm cả việc không nhận ra các lệnh tiền xử lý với khoảng trắng phía trước chúng. .

Đáng chú ý là việc loại bỏ dấu gạch chéo ngược-dòng mới xảy ra trước khi các bình luận được phân tích. Do đó, bạn không nên kết thúc //nhận xét bằng dấu gạch chéo ngược.


7

Tôi không biết tại sao nó không phổ biến hơn. Chắc chắn có những lúc tôi thích thụt lề các chỉ thị tiền xử lý.

Một điều tiếp tục cản trở tôi (và đôi khi thuyết phục tôi ngừng cố gắng) là nhiều hoặc hầu hết các biên tập viên / IDE sẽ ném chỉ thị vào cột 1 theo cách khiêu khích nhỏ nhất. Thật là khó chịu.


5

Ngày nay, tôi tin rằng đây chủ yếu là sự lựa chọn phong cách. Tôi nghĩ rằng tại một thời điểm trong quá khứ xa xôi, không phải tất cả trình biên dịch đều ủng hộ khái niệm thụt lề định nghĩa bộ xử lý trước. Tôi đã thực hiện một số nghiên cứu và không thể sao lưu khẳng định đó. Nhưng trong mọi trường hợp, có vẻ như tất cả các trình biên dịch hiện đại đều hỗ trợ ý tưởng thụt lề macro tiền xử lý. Mặc dù vậy, tôi không có bản sao của tiêu chuẩn C hoặc C ++ nên tôi không biết liệu đây có phải là hành vi tiêu chuẩn hay không.

Về việc nó có phong cách tốt hay không. Cá nhân tôi thích ý tưởng giữ tất cả chúng ở bên trái. Nó cung cấp cho bạn một nơi nhất quán để tìm kiếm chúng. Vâng, nó có thể gây khó chịu khi có các macro rất lồng nhau. Nhưng nếu bạn thụt lề chúng, cuối cùng bạn sẽ nhận được mã trông kỳ lạ hơn.

#if COND1
void foo() {
  #if COND2
  int i;
    #if COND3
  i = someFunction()
  cout << i << eol;
    #endif
  #endif
}
#endif

13
Lý do khiến mã này trông kỳ lạ là vì bạn đã tạo hai "luồng" thụt lề. Tôi sẽ thụt lề dòng 4 thêm một cấp, và tôi sẽ thụt lề dòng 6 & 7 thêm hai cấp nữa.
Kevin Laity

2
Hoàn toàn đồng ý. Đôi khi tôi thậm chí còn đặt niềng răng để # nếu của trông giống như if.
baash 05

3
Tôi rất cố gắng sắp xếp mã của mình để nó không có #ifdef dòng nào trong những phần mà tôi có mã thực. Thay vào đó, nếu tôi cần những thứ có điều kiện, tôi có thể đưa nó vào các hàm hoặc macro đã tính theo yếu tố; nó rõ ràng hơn rất nhiều theo cách tôi tìm thấy (tốt, ít nhất nó là với tôi). Lý tưởng nhất là tất cả các phần được tính theo yếu tố đó sẽ nằm trong các tệp khác (tiêu đề hoặc tệp nguồn được biên dịch có điều kiện; "điều kiện" thông thường là mã đang được xây dựng cho nền tảng nào).
Donal Fellows

2
Tôi sẽ thụt lề dòng 4 một cấp, và dòng 6 & 7 hai cấp.
Rocketmagnet 14/09/10

3

Đối với ví dụ bạn đã đưa ra, có thể thích hợp sử dụng thụt lề để làm cho nó rõ ràng hơn, vì bạn có cấu trúc phức tạp của các lệnh lồng nhau.

Cá nhân tôi nghĩ rằng sẽ rất hữu ích khi giữ chúng không bị thụt vào trong hầu hết thời gian, bởi vì các lệnh này hoạt động riêng biệt với phần còn lại của mã của bạn. Các lệnh như #ifdef được xử lý bởi bộ xử lý trước, trước khi trình biên dịch nhìn thấy mã của bạn, do đó, một khối mã sau lệnh #ifdef thậm chí có thể không được biên dịch .

Việc giữ các chỉ thị được tách biệt trực quan khỏi phần còn lại của mã của bạn quan trọng hơn khi chúng được xen kẽ với mã (thay vì một khối chỉ thị chuyên dụng, như trong ví dụ bạn đưa ra).


3
Theo quan điểm của IP, sự khác biệt giữa thứ gì đó không được biên dịch và thứ gì đó không đạt được do lỗi.
baash 05

2

Hiện tại, tôi đang làm việc trong một số mã có một hỗn hợp khủng khiếp của #defines, #ifdefs, #elses, #endifs, #etc. Tất cả những thứ này thường trộn lẫn với mã C bình thường. Việc không thụt lề của #defines khiến chúng khó đọc. Và hỗn hợp mã thụt lề với #defines không thụt lề là một cơn ác mộng.

Một giải pháp phổ biến là nhận xét các chỉ thị để bạn dễ dàng biết chúng đề cập đến:

#ifdef FOO
/* a lot of code */
#endif /* FOO */

#ifndef FOO
/* a lot of code */
#endif /* not FOO */

6
Tôi đã thấy phong cách đó, sếp của tôi sử dụng nó. Và, giống như phần còn lại của mã của anh ấy, nó chỉ tạo ra một mớ hỗn độn. Hãy tưởng tượng loại bỏ tất cả thụt lề khỏi câu lệnh if () bình thường của bạn và sử dụng các nhận xét đó thay thế. Bạn sẽ phàn nàn rằng bạn không thể dễ dàng nhìn thấy những gì họ đề cập đến.
Rocketmagnet 14/09/10

2

Trong hầu hết các trình biên dịch C / CPP hiện có, nó không bị hạn chế. Người dùng quyết định cách bạn muốn căn chỉnh mã như thế nào. Thật hạnh phúc khi viết mã.


1
Câu trả lời khéo léo. Bạn có thể cải thiện nó bằng cách thêm một số tài liệu tham khảo hướng dẫn phong cách cụ thể không?
EtherDragon
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.