2010-03-24 43 views
11

Gần đây tôi đã bị một con bọ tinh vi cắn.Tại sao cho phép nối chuỗi ký tự chuỗi?

char ** int2str = { 
    "zero", // 0 
    "one", // 1 
    "two" // 2 
    "three",// 3 
    nullptr }; 

assert(int2str[1] == std::string("one")); // passes 
assert(int2str[2] == std::string("two")); // fails 

Nếu bạn có quyền hạn đánh giá mã giống như bạn sẽ thấy, tôi đã quên , sau "two".

Sau nỗ lực đáng kể để tìm lỗi đó, tôi phải hỏi tại sao mọi người lại muốn hành vi này?

Tôi có thể thấy điều này có thể hữu ích cho ma thuật macro, nhưng tại sao đây lại là "tính năng" trong ngôn ngữ hiện đại như python?

Bạn đã từng sử dụng nối chuỗi ký tự trong mã sản xuất chưa?

+3

Tôi đã có một lỗi như thế này nhưng tôi đã có số trên các hàng khác nhau và hàng sau khi dấu phẩy bị thiếu có dấu trừ nên tôi không nhận được lỗi biên dịch. –

+0

Tôi đoán C++ 0x 'literals do người dùng xác định: http://public.research.att.com/~bs/C++0xFAQ.html#UD-literals –

+0

Trong cùng tinh thần, điều gì xảy ra nếu bạn quên '_s' sau chuỗi ký tự chuỗi? – visitor

Trả lời

4

Tôi thấy một vài CC++ câu trả lời nhưng không có thực sự trả lời tại sao hoặc thực sự là lý do cho tính năng này là gì? Trong C++ đây là tính năng xuất phát từ C99 và chúng ta có thể tìm ra lý do cho tính năng này bằng cách vào Rationale for International Standard—Programming Languages—C phần 6.4.5literals Chuỗi mà nói (nhấn mạnh tôi):

Một chuỗi có thể tiếp tục trên nhiều dòng bằng cách sử dụng tiếp tục dòng ngược - dòng mới, nhưng điều này đòi hỏi rằng sự tiếp tục của chuỗi bắt đầu ở vị trí đầu tiên của dòng tiếp theo. Để cho phép bố cục linh hoạt hơn và để giải quyết một số vấn đề tiền xử lý (xem §6.10.3), Ủy ban C89 đã giới thiệu nối chuỗi ký tự. Hai chuỗi ký tự trong một hàng được dán lại với nhau, không có ký tự rỗng ở giữa, để tạo một chuỗi ký tự kết hợp. Việc bổ sung này vào ngôn ngữ C cho phép một lập trình viên mở rộng chuỗi ký tự vượt quá phần cuối của một dòng vật lý mà không phải sử dụng cơ chế backslash – newline và do đó phá hủy lược đồ thụt đầu dòng của chương trình. Một toán tử ghép nối rõ ràng không được giới thiệu vì kết nối là một cấu trúc từ vựng thay vì hoạt động thời gian chạy.

Python mà dường như có lý do tương tự, điều này làm giảm nhu cầu xấu xí \ để tiếp tục xâu dài. Được bao gồm trong phần 2.4.2 String literal concatenation của số Tham chiếu ngôn ngữ Python.

+0

Điều này có vẻ là lý do thực sự _Một nhà điều hành ghép nối rõ ràng đã không được giới thiệu bởi vì nối là một cấu trúc từ vựng chứ không phải là một hoạt động thời gian chạy_. Mọi người khác chỉ theo sau. –

+0

Điều này cực kỳ hữu ích nếu bạn cần phải đại diện cho một lượng lớn văn bản trong C literals. Ví dụ: một thông báo "sử dụng" dài cho các chương trình CLI hoặc nếu bạn không đủ khả năng để viết các chương trình CGI trong C. –

0

Tôi chắc chắn có cả C và C++. Trái phép, tôi không thấy nhiều mối quan hệ giữa tiện ích của nó và ngôn ngữ "hiện đại" như thế nào.

+0

Tôi không có nghĩa là các ngôn ngữ cũ không nên được sử dụng hiện đại. Tôi đã đề cập đến khi thông số ngôn ngữ ban đầu được viết. C# chắc chắn đã học được từ Java và tránh mụn cóc của nó. Điều này cũng đúng cho việc học Java/C# từ C++. –

1

Để bạn có thể chia các chuỗi ký tự chuỗi dài trên các dòng.

Và có, tôi đã nhìn thấy nó trong mã sản xuất.

5

Những trường hợp này có thể hữu ích:

  • chuỗi Tạo bao gồm các thành phần được xác định bằng vi xử lý (điều này có lẽ là trường hợp sử dụng lớn nhất trong C, và đó là một trong tôi thấy rất, rất thường xuyên).
  • chuỗi hằng Splitting trên nhiều dòng

Để cung cấp một ví dụ cụ thể hơn cho các cựu:

// in version.h 
#define MYPROG_NAME "FOO" 
#define MYPROG_VERSION "0.1.2" 

// in main.c 
puts("Welcome to " MYPROG_NAME " version " MYPROG_VERSION "."); 
17

Đó là một tính năng tuyệt vời cho phép bạn kết hợp chuỗi tiền xử lý với chuỗi của bạn.

// Here we define the correct printf modifier for time_t 
#ifdef TIME_T_LONG 
    #define TIME_T_MOD "l" 
#elif defined(TIME_T_LONG_LONG) 
    #define TIME_T_MOD "ll" 
#else 
    #define TIME_T_MOD "" 
#endif 

// And he we merge the modifier into the rest of our format string 
printf("time is %" TIME_T_MOD "u\n", time(0)); 
+0

+1, đó là lý do kỹ thuật tốt nhất. Hệ thống cũng định nghĩa một số kiểu như vậy - câu trả lời của tôi có một ví dụ. –

+0

Lý do kỹ thuật tốt nhất, nếu bạn bỏ qua thực tế là bạn thực sự không nên sử dụng bộ tiền xử lý để thực hiện loại điều này ngay từ đầu ... –

+1

@STingRaySC, còn «PRIx32' hoặc' PRIuLEAST32' và bạn bè thì sao? http://www.opengroup.org/onlinepubs/9699919799/basedefs/inttypes.h.html –

22

Chắc chắn, đó là cách dễ dàng để làm cho mã của bạn trông tốt:

char *someGlobalString = "very long " 
         "so broken " 
         "onto multiple " 
         "lines"; 

Lý do tốt nhất, tuy nhiên, là cho các định dạng printf lạ, giống như kiểu buộc:

uint64_t num = 5; 
printf("Here is a number: %"PRIX64", what do you think of that?", num); 

Có một loạt những người được xác định, và họ có thể có ích nếu bạn có yêu cầu kích thước loại. Kiểm tra tất cả chúng ra at this link. Một vài ví dụ:

PRIo8 PRIoLEAST16 PRIoFAST32 PRIoMAX PRIoPTR 
+0

@Carl - bạn nên sửa đổi ví dụ printf của mình để có đối số 'uint64_t'. –

+0

Cảm ơn vì điều đó! Đã sửa. –

2

Tôi không chắc chắn về các ngôn ngữ lập trình khác, nhưng C# không cho phép bạn làm điều này (và tôi nghĩ đây là một điều tốt). Theo như tôi có thể nói, hầu hết các ví dụ cho thấy tại sao điều này rất hữu ích trong C++ vẫn có thể làm việc nếu bạn có thể sử dụng một số nhà điều hành đặc biệt cho chuỗi nối:

string someGlobalString = "very long " + 
          "so broken " + 
          "onto multiple " + 
          "lines"; 

Điều này có thể không được như thoải mái, nhưng nó là chắc chắn an toàn hơn. Trong ví dụ thúc đẩy của bạn, mã sẽ không hợp lệ trừ khi bạn thêm , để phân tách các phần tử hoặc + để ghép các chuỗi ...

+0

Điều đó sẽ không hợp lệ. Ít nhất một trong những chuỗi đó sẽ phải có một diễn viên để std :: string trước đó sẽ biên dịch. Ngoài ra, câu hỏi được gắn thẻ với C. –

+0

@BillyONeal: Câu hỏi được gắn thẻ bằng Python/C++ và nó hỏi tại sao "các ngôn ngữ hiện đại như Python" cho phép điều này, vì vậy tôi nghĩ tôi sẽ đăng một ví dụ ngược lại. Và tôi muốn cho thấy rằng bạn không cần tính năng này (nói chung) để hỗ trợ những thứ như ngắt dòng và mở rộng macro. –

+0

Hmm .. tôi đã hút thuốc gì? +1 –

3

Từ trăn tham khảo phân tích từ vựng, phần 2.4.2:

Tính năng này có thể được sử dụng để giảm số của backslashes cần thiết, để chia chuỗi dài thuận tiện trên đường dài, hoặc thậm chí để thêm ý kiến ​​để bộ phận của chuỗi

http://docs.python.org/reference/lexical_analysis.html

+0

Chuỗi '' 'có giống nhau không? –

+0

@Caspin - một chuỗi thô (r '' hoặc được trích dẫn ba lần) sẽ bao gồm tất cả các ký tự và khoảng trắng mới. Các chuỗi ký tự chuỗi riêng biệt sẽ chỉ được ghép nối. – JimB

0

trong khi peo ple đã đưa những lời ra khỏi miệng của tôi về việc sử dụng thực tế của tính năng này, không ai cho đến nay đã cố gắng để bảo vệ sự lựa chọn của cú pháp.

Đối với tất cả những gì tôi biết, lỗi đánh máy có thể trượt qua kết quả là có lẽ chỉ bị bỏ qua. Sau khi tất cả, có vẻ như mạnh mẽ chống lại lỗi chính tả không phải ở phía trước của tâm của Dennis, như thể hiện hơn nữa bằng cách:

if (a = b); 
{ 
    printf("%d", a); 
} 

Bên cạnh đó, có quan điểm có thể là nó không phải là giá trị sử dụng lên một biểu tượng thêm cho nối của chuỗi chữ - sau khi tất cả, không có gì khác mà có thể được thực hiện với hai người trong số họ, và có một biểu tượng có thể tạo ra sự cám dỗ để cố gắng sử dụng nó cho chuỗi nối thời gian chạy, mà là ở trên mức độ của C được xây dựng trong các tính năng .

Một số ngôn ngữ cấp cao, hiện đại dựa trên cú pháp C đã loại bỏ ký hiệu này có lẽ vì nó dễ bị lỗi. Nhưng các ngôn ngữ này có một toán tử cho phép nối chuỗi, chẳng hạn như + (JS, C#), . (Perl, PHP), ~ (D, mặc dù điều này cũng đã giữ cú pháp juxtaposition của C) và gấp liên tục (bằng ngôn ngữ được biên dịch) có nghĩa là không có chi phí hiệu năng thời gian chạy.

1

Đối với lý do, mở rộng và đơn giản hóa câu trả lời Shafik Yaghmour của: nối chuỗi đen có nguồn gốc trong C (do đó được thừa kế bởi C++), cũng như thuật ngữ, vì hai lý do (tài liệu tham khảo là từ Rationale for the ANSI C Programming Language):

  • Đối với định dạng: để cho phép các chuỗi ký tự chuỗi dài trải dài nhiều dòng với thụt đầu dòng thích hợp - trái ngược với dòng tiếp tục, phá hủy sơ đồ thụt đầu dòng (3.1.4 String literals); và
  • Đối với ma thuật macro: để cho phép tạo chuỗi ký tự bằng các macro (thông qua việc xâu chuỗi) (3.8.3.2 The # operator).

Nó được bao gồm trong ngôn ngữ hiện đại Python và D vì chúng sao chép từ C, mặc dù cả hai đã được đề xuất không dùng nữa vì nó dễ bị lỗi (như bạn lưu ý) và không cần thiết (vì người ta chỉ có thể có một toán tử nối và constant folding để đánh giá thời gian biên dịch; bạn không thể làm điều này trong C vì chuỗi là con trỏ, và vì vậy bạn không thể thêm chúng). Nó không đơn giản để loại bỏ bởi vì nó phá vỡ tính tương thích, và bạn phải cẩn thận về ưu tiên (nối liên tục xảy ra trong khi lexing, trước khi khai thác, nhưng thay thế điều này với một nhà điều hành có nghĩa là bạn cần phải cẩn thận về ưu tiên), do đó tại sao nó vẫn còn hiện diện.

Có, nó đang được sử dụng trong mã sản xuất. Google Python Style Guide: Line length chỉ định:

Khi chuỗi chữ không khớp trên một dòng, hãy sử dụng dấu ngoặc đơn để nối dòng.

x = ('This will build a very long long ' 
    'long long long long long long string') 

Xem “String literal concatenation” tại Wikipedia để biết thêm chi tiết và tài liệu tham khảo.

+0

Điểm tuyệt vời mà nếp gấp liên tục loại bỏ tất cả lợi thế. Điều này thậm chí có thể làm việc trong C/C++ nếu chỉ giới hạn trong các chuỗi ký tự chuỗi. –

+0

Cảm ơn! Đúng là các chuỗi ký tự có thể là đặc biệt, mặc dù đó cũng là một hack, và gây nhầm lẫn theo cách riêng của nó: tại sao '" foo "+" bar "' làm việc nhưng 'string s =" bar "; "foo" + s' không? Tôi nghĩ rằng lý do là các chuỗi ký tự được quyết định kiểu 'char []' (C)/'const char []' (C++). Tuy nhiên, nó * làm * làm việc trong C++ 14 với chuỗi ký tự chuẩn mới (với 's' hậu tố):' "foo" s + "bar" s' là hợp lệ, và có thể gấp. –

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