2010-03-25 31 views
11

Nó đã luôn luôn đánh tôi như là lạ rằng chức năng C "fopen" có một "const char *" là đối số thứ hai. Tôi nghĩ rằng nó sẽ được dễ dàng hơn cho cả hai đọc mã của bạn và triển khai mã của thư viện nếu có mặt nạ bit được định nghĩa trong stdio.h, như "IO_READ" và như vậy, vì vậy bạn có thể làm những việc như:Tại sao "fopen" của C lại lấy "const char *" làm đối số thứ hai của C?

FILE* myFile = fopen("file.txt", IO_READ | IO_WRITE); 

Is có một lý do có lập trình cho cách nó thực sự là, hoặc là nó chỉ là lịch sử? (ví dụ: "Đó chỉ là cách của nó.")

EDIT Cảm ơn mọi người đã giải thích. Câu trả lời đúng có lẽ nằm trong số những câu trả lời được đưa ra.

+0

Wiki cộng đồng? – Romain

+5

@Romain: Không, có câu trả lời rõ ràng ở đây. – GManNickG

Trả lời

5

Một từ: cũ. Thật không may, chúng ta phải sống với nó.

Chỉ cần suy đoán: Có thể tại thời điểm "const char *" có vẻ là giải pháp linh hoạt hơn, bởi vì nó không bị giới hạn theo bất kỳ cách nào. Một mặt nạ bit chỉ có thể có 32 giá trị khác nhau. Hình như YAGNI với tôi bây giờ.

Thêm suy đoán: Dudes lười và viết "rb" yêu cầu nhập ít hơn MASK_THIS | MASK_THAT :)

+0

Tại sao? Mặt nạ có vẻ là sự lựa chọn tự nhiên ở đây, đặc biệt là trong ngày 'fopen' được thiết kế. – GManNickG

+0

@GMan: Khi tôi suy đoán trong câu trả lời của mình, tôi tự hỏi liệu thời gian của các lập trình viên có được coi là tài nguyên có giá trị hơn không. Nhưng tôi không có bằng chứng thực sự. –

+0

@GMan: Tôi không chắc chắn mặt nạ nhất thiết phải là sự lựa chọn tự nhiên * nhiều hơn một bộ mô tả chuỗi. Hoặc là các tùy chọn thiết kế hợp lý, có thể bảo vệ. –

0

Như Tuomas Pelkonen nói, đó là di sản.

Cá nhân, tôi tự hỏi nếu một số saps sai lầm hình thành nó như là tốt hơn do ít ký tự gõ? Trong những ngày xa xưa, các lập trình viên đã được đánh giá cao hơn ngày hôm nay, vì nó ít được tiếp cận và các trình biên dịch không phải là tuyệt vời và tất cả những điều đó.

Đây chỉ là suy đoán, nhưng tôi có thể thấy lý do tại sao một số người ủng hộ việc tiết kiệm một vài ký tự ở đây và ở đó (chú ý sự thiếu độ dài trong bất kỳ tên hàm thư viện chuẩn nào… Tôi trình bày "strstr" của string.h và "strchr" có lẽ là ví dụ tốt nhất về ngắn gọn không cần thiết).

+4

Việc thiếu độ dài trong tên thư viện là vì họ muốn hỗ trợ các hệ thống chỉ hỗ trợ 6 ký tự quan trọng trong các tên bên ngoài. Hãy nhớ rằng C đã được định nghĩa, từ lâu, và không phải tất cả các hệ thống đều hỗ trợ công cụ tuyệt vời. –

+0

Điểm tốt, mặc dù điều đó không giải thích fprintf và sprintf. Tôi đoán những người có thể đã được xác định sau đó, mặc dù, và tôi sẽ thừa nhận tôi quá lười biếng để tìm kiếm lịch sử vào lúc này. –

+0

Bạn không nhớ nhập mã trên các loại máy điện thoại! –

1

Tôi phải nói rằng tôi biết ơn về điều đó - mà tôi biết để gõ "r" thay vì IO_OPEN_FLAG_R hay là IOFLAG_R hoặc SYSFLAGS_OPEN_RMODE hoặc bất cứ điều gì

+1

Điều này thực sự là một điểm thực sự tốt, nó là dễ dàng hơn nhiều để nhớ các API. –

+0

Tôi phải nói rằng tôi không đồng ý với bạn. Tôi sẽ có thể nói những gì một cuộc gọi chức năng bằng cách nhìn vào các đối số của nó. Bạn không thể làm điều đó chỉ với một "r". "R" có nghĩa là gì? Bạn không thể nói mà không đọc tài liệu về chức năng được đề cập. –

+0

@Tuomas Pelkonen: Dễ nhớ hơn khi viết, nhưng đó là một nỗi đau ở mông sau khi bạn đọc. Vì mã được đọc thường xuyên hơn nhiều so với nó được viết, tôi muốn tối ưu hóa cho trường hợp đọc chứ không phải là viết trường hợp. –

3

tôi suy đoán rằng đó là một hoặc nhiều điều sau đây (không may , tôi đã không thể nhanh chóng tìm thấy bất kỳ loại tài liệu tham khảo hỗ trợ, vì vậy điều này có lẽ sẽ vẫn suy đoán):

  1. Kernighan hoặc Ritchie (hoặc bất cứ ai đã đưa ra giao diện cho fopen()) vừa xảy ra để thích ý tưởng về cách xác định chế độ sử dụng chuỗi thay vì bitmap
  2. Họ có thể đã muốn giao diện là tương tự như chưa đáng chú ý khác với Unix open() giao diện hệ thống gọi, vì vậy nó sẽ ngay lập tức quen thuộc nhưng không nhầm lẫn biên dịch với các hằng số định nghĩa cho Unix thay vì bởi các thư viện C

Đối ví dụ, giả sử tiêu chuẩn C huyền thoại fopen() lấy tham số chế độ bitmap được sử dụng mã định danh OPENMODE_READONLY để chỉ định tệp ngày nay được chỉ định bởi chuỗi chế độ "r". Bây giờ, nếu ai đó thực hiện cuộc gọi sau đây trên một chương trình biên soạn trên một nền tảng Unix (và rằng tiêu đề định nghĩa O_RDONLY đã được bao gồm):

fopen("myfile", O_RDONLY); 

Sẽ không có lỗi biên dịch, nhưng trừ khi OPENMODE_READONLYO_RDONLY được xác định để được cùng một bit bạn sẽ nhận được hành vi bất ngờ.Tất nhiên nó sẽ có ý nghĩa cho các tên tiêu chuẩn C được định nghĩa giống như tên Unix, nhưng có lẽ họ muốn loại trừ yêu cầu loại khớp nối này.

Sau đó, một lần nữa, điều này có thể không vượt qua tâm trí của họ ở tất cả ...

1

Dennis Ritchie đã cho biết, từ http://cm.bell-labs.com/cm/cs/who/dmr/chist.html

Đặc biệt, Lesk viết một 'di I/O gói '[Lesk 72] đó là sau làm lại để trở thành C' chuẩn I/O' thói quen

Vì vậy, tôi nói hỏi Mike Lesk, đăng r esult ở đây như là một câu trả lời cho câu hỏi của riêng bạn, và kiếm được đống điểm cho nó. Mặc dù bạn có thể muốn làm cho câu hỏi nghe có vẻ ít lời chỉ trích hơn ;-)

+0

Không có kiểu dữ liệu nào như const char * khi Lesk viết gói đó. Không chờ đợi. Không rõ ràng kiểu dữ liệu có thể hoặc có thể không tồn tại tùy thuộc vào cách thực hiện xử lý hằng số chuỗi, nhưng không có cách nào cho một lập trình viên C chỉ định kiểu dữ liệu đó trong một chương trình. –

+0

Đúng, nhưng sau đó 'const' không tồn tại khi' strlen' được phát minh, nhưng tôi không nghĩ chúng ta có thể kết luận từ điều này, rằng 'strlen' có lẽ ban đầu lấy bất kỳ tham số nào ngoài con trỏ chuỗi ;-) Nó chỉ là cách điển hình để nói "một chuỗi" thay đổi. –

1

Tôi tin rằng một trong những ưu điểm của chuỗi ký tự thay vì một mặt nạ bit đơn giản là nó cho phép các tiện ích mở rộng nền tảng cụ thể không phải bit-settings. Hoàn toàn giả thuyết:

FILE *fp = fopen("/dev/something-weird", "r+:bs=4096"); 

Đối với Gizmo này, cuộc gọi open() cần phải được cho biết kích thước khối, và các cuộc gọi khác nhau có thể sử dụng kích thước hoàn toàn khác nhau, vv Cấp, I/O đã được tổ chức khá tốt hiện nay (như vậy là không phải là trường hợp ban đầu - các thiết bị rất đa dạng và các cơ chế truy cập xa hợp nhất), vì vậy hiếm khi có vẻ là cần thiết. Nhưng chuỗi tùy chọn có giá trị chuỗi cho phép khả năng mở rộng đó tốt hơn nhiều.

Phần dưới open() phải được tăng cường bởi các cuộc gọi hoặc chức năng của cuộc gọi ioctl() (I/O control) để ẩn nó để đạt được các hiệu ứng tương tự.

+0

Cảm ơn Jonathan. Đó là một lợi thế thú vị khác của các chuỗi mà tôi không biết. –

1

Các tài liệu tham khảo sớm nhất để fopen mà tôi đã tìm thấy là trong ấn bản đầu tiên của "The C Programming Language" (K & R1) Kernighan & của Ritchie, được công bố vào năm 1978.

Nó cho thấy một thực hiện mẫu fopen , có lẽ là một phiên bản đơn giản của mã trong việc thực hiện thư viện chuẩn C thời gian. Dưới đây là một phiên bản rút gọn của mã từ cuốn sách:

FILE *fopen(name, mode) 
register char *name, *mode; 
{ 
    /* ... */ 
    if (*mode != 'r' && *mode != 'w' && *mode != 'a') { 
     fprintf(stderr, "illegal mode %s opening %s\n", 
      mode, name); 
     exit(1); 
    } 
    /* ... */ 
} 

Nhìn vào mã, mode được dự kiến ​​sẽ là một chuỗi 1 ký tự (không "rb", không có sự phân biệt giữa văn bản và nhị phân). Nếu bạn đã vượt qua chuỗi dài hơn, bất kỳ ký tự nào trong quá khứ đầu tiên đều bị bỏ qua âm thầm. Nếu bạn đã vượt qua mode không hợp lệ, chức năng sẽ in thông báo lỗi và chấm dứt chương trình của bạn thay vì trả về một con trỏ rỗng (tôi đoán phiên bản thư viện thực sự không làm điều đó). Cuốn sách nhấn mạnh mã đơn giản về kiểm tra lỗi.

Thật khó để chắc chắn, nhất là khi sách không mất nhiều thời gian để giải thích tham số mode, nhưng có vẻ như nó đã được xác định là một chuỗi chỉ để thuận tiện. Một nhân vật duy nhất cũng có thể làm việc, nhưng một chuỗi ít nhất làm cho việc mở rộng trong tương lai có thể xảy ra (một cái gì đó mà cuốn sách không đề cập đến).

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