Tại sao chức năng get lại nguy hiểm đến mức không nên sử dụng?


229

Khi tôi cố gắng biên dịch mã C sử dụng gets()hàm với GCC, tôi nhận được cảnh báo này:

(.text + 0x34): cảnh báo: chức năng `got 'là nguy hiểm và không nên được sử dụng.

Tôi nhớ điều này có liên quan đến bảo vệ và bảo mật ngăn xếp, nhưng tôi không chắc chính xác tại sao.

Làm cách nào tôi có thể xóa cảnh báo này và tại sao lại có cảnh báo như vậy về việc sử dụng gets()?

Nếu gets()quá nguy hiểm thì tại sao chúng ta không thể loại bỏ nó?



Câu trả lời:


179

Để sử dụng getsmột cách an toàn, bạn phải biết chính xác có bao nhiêu ký tự bạn sẽ đọc, để bạn có thể làm cho bộ đệm của mình đủ lớn. Bạn sẽ chỉ biết rằng nếu bạn biết chính xác dữ liệu nào bạn sẽ đọc.

Thay vì sử dụng gets, bạn muốn sử dụng fgets, có chữ ký

char* fgets(char *string, int length, FILE * stream);

( fgets, nếu nó đọc toàn bộ một dòng, sẽ để lại '\n'chuỗi; bạn sẽ phải xử lý vấn đề đó.)

Nó vẫn là một phần chính thức của ngôn ngữ theo tiêu chuẩn ISO C năm 1999, nhưng nó đã chính thức bị loại bỏ bởi tiêu chuẩn năm 2011. Hầu hết các triển khai C vẫn hỗ trợ nó, nhưng ít nhất gcc đưa ra cảnh báo cho bất kỳ mã nào sử dụng nó.


79
Nó thực sự không phải là gcc cảnh báo, đó là glibc chứa pragma hoặc thuộc tính trên gets()đó khiến trình biên dịch phát ra cảnh báo khi sử dụng.
fuz

@fuz thực sự, nó thậm chí không chỉ là trình biên dịch cảnh báo: cảnh báo được trích dẫn trong OP đã được in bởi trình liên kết!
Ruslan

163

Tại sao gets()nguy hiểm

Con sâu internet đầu tiên ( Worm Internet Internet ) đã trốn thoát khoảng 30 năm trước (1988-11 / 02), và nó đã sử dụng gets()và tràn bộ đệm như một trong những phương pháp truyền từ hệ thống này sang hệ thống khác. Vấn đề cơ bản là hàm không biết bộ đệm lớn đến mức nào, vì vậy nó tiếp tục đọc cho đến khi tìm thấy dòng mới hoặc gặp EOF và có thể vượt quá giới hạn của bộ đệm được cung cấp.

Bạn nên quên bạn đã từng nghe rằng gets()tồn tại.

Tiêu chuẩn C11 ISO / IEC 9899: 2011 đã bị loại bỏ gets()như một chức năng tiêu chuẩn, đó là A Good Thing ™ (nó được đánh dấu chính thức là 'lỗi thời' và 'không dùng nữa' trong ISO / IEC 9899: 1999 / Cor.3: 2007 - Bản sửa lỗi kỹ thuật 3 cho C99, và sau đó loại bỏ trong C11). Đáng buồn thay, nó sẽ tồn tại trong các thư viện trong nhiều năm (có nghĩa là 'thập kỷ') vì lý do tương thích ngược. Nếu nó tùy thuộc vào tôi, việc thực hiện gets()sẽ trở thành:

char *gets(char *buffer)
{
    assert(buffer != 0);
    abort();
    return 0;
}

Dù rằng mã của bạn sẽ bị sập dù thế nào, sớm hay muộn, tốt hơn là nên giải quyết vấn đề sớm hơn là muộn hơn. Tôi đã sẵn sàng để thêm một thông báo lỗi:

fputs("obsolete and dangerous function gets() called\n", stderr);

Các phiên bản hiện đại của hệ thống biên dịch Linux tạo cảnh báo nếu bạn liên kết gets()- và cả một số chức năng khác cũng có vấn đề về bảo mật ( mktemp(), khắc).

Các lựa chọn thay thế cho gets()

fget ()

Như mọi người khác đã nói, sự thay thế chính tắc gets()được fgets()chỉ định stdinlà luồng tệp.

char buffer[BUFSIZ];

while (fgets(buffer, sizeof(buffer), stdin) != 0)
{
    ...process line of data...
}

Điều mà không ai khác đề cập là gets()không bao gồm dòng mới nhưng fgets()không có. Vì vậy, bạn có thể cần phải sử dụng một trình bao bọc xung quanh fgets()để xóa dòng mới:

char *fgets_wrapper(char *buffer, size_t buflen, FILE *fp)
{
    if (fgets(buffer, buflen, fp) != 0)
    {
        size_t len = strlen(buffer);
        if (len > 0 && buffer[len-1] == '\n')
            buffer[len-1] = '\0';
        return buffer;
    }
    return 0;
}

Hoặc tốt hơn:

char *fgets_wrapper(char *buffer, size_t buflen, FILE *fp)
{
    if (fgets(buffer, buflen, fp) != 0)
    {
        buffer[strcspn(buffer, "\n")] = '\0';
        return buffer;
    }
    return 0;
}

Ngoài ra, như quán cà phê chỉ ra trong một bình luận và paxdiablo hiển thị trong câu trả lời của anh ấy, với fgets()bạn có thể có dữ liệu còn sót lại trên một dòng. Mã trình bao bọc của tôi để dữ liệu đó được đọc lần sau; bạn có thể dễ dàng sửa đổi nó để ngấu nghiến phần còn lại của dòng dữ liệu nếu bạn thích:

        if (len > 0 && buffer[len-1] == '\n')
            buffer[len-1] = '\0';
        else
        {
             int ch;
             while ((ch = getc(fp)) != EOF && ch != '\n')
                 ;
        }

Vấn đề còn lại là làm thế nào để báo cáo ba trạng thái kết quả khác nhau - EOF hoặc lỗi, đọc dòng và không bị cắt, và đọc một phần dòng nhưng dữ liệu đã bị cắt ngắn.

Vấn đề này không xảy ra gets()vì nó không biết bộ đệm của bạn kết thúc ở đâu và vui vẻ vượt quá cuối, phá hỏng bố cục bộ nhớ được chăm sóc đẹp mắt của bạn, thường làm rối ngăn xếp trở lại ( tràn ngăn xếp ) nếu bộ đệm được cấp phát ngăn xếp hoặc chà đạp lên thông tin điều khiển nếu bộ đệm được phân bổ động hoặc sao chép dữ liệu qua các biến toàn cục (hoặc mô-đun) quý giá khác nếu bộ đệm được phân bổ tĩnh. Không ai trong số này là một ý tưởng hay - họ mô tả cụm từ 'hành vi không xác định`.


Ngoài ra còn có TR 24731-1 (Báo cáo kỹ thuật từ Ủy ban tiêu chuẩn C) cung cấp các lựa chọn thay thế an toàn hơn cho nhiều chức năng, bao gồm gets():

§6.5.4.1 gets_sHàm

Tóm tắc

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
char *gets_s(char *s, rsize_t n);

Hạn chế thời gian chạy

ssẽ không phải là một con trỏ null nsẽ không bằng 0 và không lớn hơn RSIZE_MAX. Một ký tự dòng mới, cuối tập tin hoặc lỗi đọc sẽ xảy ra trong khi đọc các n-1ký tự từ stdin. 25)

3 Nếu có vi phạm ràng buộc thời gian chạy, s[0]được đặt thành ký tự null và các ký tự được đọc và loại bỏ stdincho đến khi một ký tự dòng mới được đọc, hoặc kết thúc tệp hoặc xảy ra lỗi đọc.

Sự miêu tả

4 gets_sHàm đọc tối đa một ít hơn số lượng ký tự được chỉ định n từ luồng được trỏ tới stdin, vào mảng được chỉ bởi s. Không có ký tự bổ sung nào được đọc sau ký tự dòng mới (bị loại bỏ) hoặc sau khi kết thúc tệp. Ký tự dòng mới bị loại bỏ không được tính vào số lượng ký tự được đọc. Một ký tự null được viết ngay sau ký tự cuối cùng được đọc vào mảng.

5 Nếu gặp phải tập tin cuối và không có ký tự nào được đọc vào mảng hoặc nếu xảy ra lỗi đọc trong quá trình thao tác, thì s[0]được đặt thành ký tự null và các thành phần khác của các sgiá trị không xác định.

Đề nghị thực hành

6 fgetsHàm cho phép các chương trình được viết đúng để xử lý một cách an toàn các dòng đầu vào quá lâu để lưu trữ trong mảng kết quả. Nói chung, điều này đòi hỏi người gọi fgetsphải chú ý đến sự hiện diện hoặc vắng mặt của một ký tự dòng mới trong mảng kết quả. Cân nhắc sử dụng fgets(cùng với bất kỳ xử lý cần thiết nào dựa trên các ký tự dòng mới) thay vì gets_s.

25) Các gets_schức năng, không giống như gets, làm cho nó một sự vi phạm runtime-hạn chế cho một dòng đầu vào làm tràn bộ đệm để lưu trữ nó. Không giống như fgets, gets_sduy trì mối quan hệ một-một giữa các dòng đầu vào và các cuộc gọi thành công gets_s. Các chương trình sử dụng getsmong đợi một mối quan hệ như vậy.

Trình biên dịch Microsoft Visual Studio triển khai xấp xỉ với tiêu chuẩn TR 24731-1, nhưng có sự khác biệt giữa các chữ ký được Microsoft triển khai và các chữ ký trong TR.

Tiêu chuẩn C11, ISO / IEC 9899-2011, bao gồm TR24731 trong Phụ lục K là một phần tùy chọn của thư viện. Thật không may, nó hiếm khi được thực hiện trên các hệ thống giống như Unix.


getline() - POSIX

POSIX 2008 cũng cung cấp một sự thay thế an toàn để gets()gọi getline(). Nó phân bổ không gian cho dòng một cách linh hoạt, vì vậy cuối cùng bạn cần giải phóng nó. Do đó, nó loại bỏ giới hạn về độ dài dòng. Nó cũng trả về độ dài của dữ liệu đã đọc, hoặc -1(và không EOF!), Điều đó có nghĩa là các byte rỗng trong đầu vào có thể được xử lý một cách đáng tin cậy. Ngoài ra còn có một biến thể 'chọn ký tự phân cách một ký tự của riêng bạn được gọi là getdelim(); điều này có thể hữu ích nếu bạn đang xử lý đầu ra từ find -print0nơi kết thúc của tên tệp được đánh dấu bằng ký tự ASCII NUL '\0'.


8
Cũng đáng để chỉ ra rằng fgets()fgets_wrapper()phiên bản của bạn sẽ để lại phần đuôi của một dòng quá dài trong bộ đệm đầu vào, để được đọc bởi chức năng đầu vào tiếp theo. Trong nhiều trường hợp, bạn sẽ muốn đọc và loại bỏ các ký tự này.
phê

5
Tôi tự hỏi tại sao họ không thêm một thay thế fgets () cho phép một người sử dụng chức năng của nó mà không phải thực hiện một cuộc gọi strlen ngớ ngẩn. Ví dụ, một biến thể fget trả về số byte được đọc vào chuỗi sẽ giúp mã dễ dàng xem liệu lần đọc byte cuối cùng có phải là một dòng mới hay không. Nếu hành vi chuyển một con trỏ null cho bộ đệm được định nghĩa là "đọc và loại bỏ tối đa n-1 byte cho đến dòng mới tiếp theo", điều đó sẽ cho phép mã dễ dàng loại bỏ phần đuôi của các dòng quá dài.
supercat

2
@supercat: Vâng, tôi đồng ý - thật đáng tiếc. Cách tiếp cận gần nhất có lẽ là POSIX getline()và họ hàng của nó getdelim(), trả về độ dài của 'dòng' được đọc bởi các lệnh, phân bổ không gian theo yêu cầu để có thể lưu trữ toàn bộ dòng. Thậm chí điều đó có thể gây ra vấn đề nếu bạn kết thúc với một tệp JSON một dòng có kích thước nhiều gigabyte; bạn có thể đủ khả năng cho tất cả bộ nhớ? (Và trong khi chúng ta đang ở đó, chúng ta có thể có strcpy()strcat()các biến thể trả về một con trỏ đến byte null ở cuối không? V.v.)
Jonathan Leffler

4
@supercat: vấn đề khác fgets()là nếu tệp chứa byte rỗng, bạn không thể biết có bao nhiêu dữ liệu sau byte null cho đến cuối dòng (hoặc EOF). strlen()chỉ có thể báo cáo tối đa byte null trong dữ liệu; sau đó, đó là phỏng đoán và do đó gần như chắc chắn sai.
Jonathan Leffler

7
"quên bạn từng nghe rằng gets()đã tồn tại." Khi tôi làm điều này, tôi gặp lại nó và quay lại đây. Bạn đang hack stackoverflow để có được upvotes?
candied_orange

21

Bởi vì getskhông thực hiện bất kỳ loại kiểm tra nào trong khi nhận byte từ stdin và đặt chúng ở đâu đó. Một ví dụ đơn giản:

char array1[] = "12345";
char array2[] = "67890";

gets(array1);

Bây giờ, trước hết bạn được phép nhập bao nhiêu ký tự bạn muốn, getssẽ không quan tâm đến nó. Thứ hai, các byte trên kích thước của mảng mà bạn đặt chúng (trong trường hợp này array1) sẽ ghi đè lên bất cứ thứ gì chúng tìm thấy trong bộ nhớ vì getssẽ ghi chúng. Trong ví dụ trước, điều này có nghĩa là nếu bạn nhập "abcdefghijklmnopqrts"có thể, không thể đoán trước, nó sẽ ghi đè lên array2hoặc bất cứ điều gì.

Hàm này không an toàn vì nó giả sử đầu vào nhất quán. KHÔNG BAO GIỜ SỬ DỤNG NÓ!


3
Điều khiến cho getshoàn toàn không sử dụng được là nó không có tham số đếm chiều dài / số mà nó cần; nếu nó ở đó, nó sẽ chỉ là một chức năng tiêu chuẩn C thông thường khác.
huyền thoại2k

@ legends2k: Tôi tò mò không biết mục đích sử dụng getslà gì và tại sao không có biến thể fget tiêu chuẩn nào được thực hiện thuận tiện cho các trường hợp sử dụng mà dòng mới không mong muốn như một phần của đầu vào?
supercat

1
@supercat gets, như tên cho thấy, được thiết kế để lấy một chuỗi từ stdin, tuy nhiên lý do không có tham số kích thước có thể xuất phát từ tinh thần của C : Tin tưởng vào lập trình viên. Hàm này đã bị loại bỏ trong C11 và sự thay thế đã cho gets_scó kích thước của bộ đệm đầu vào. Tôi không có manh mối về fgetsphần mặc dù.
huyền thoại2k

@ legends2k: Bối cảnh duy nhất tôi có thể thấy trong đó getscó thể dễ dàng sử dụng là nếu một người đang sử dụng hệ thống I / O được đệm phần cứng không thể gửi một dòng trên một độ dài nhất định và thời gian dự định của chương trình đã ngắn hơn tuổi thọ của phần cứng. Trong trường hợp đó, nếu phần cứng không có khả năng gửi các dòng dài hơn 127 byte thì có thể chính đáng để getsvào bộ đệm 128 byte, mặc dù tôi nghĩ rằng những lợi thế của việc có thể chỉ định bộ đệm ngắn hơn khi mong đợi đầu vào nhỏ hơn sẽ hợp lý hơn Giá cả.
supercat

@ legends2k: Trên thực tế, những gì có thể là lý tưởng sẽ có một "con trỏ chuỗi" xác định một byte sẽ chọn trong số một vài định dạng chuỗi / bộ đệm / bộ đệm-thông tin khác nhau, với một giá trị của byte tiền tố chỉ ra một cấu trúc có chứa byte tiền tố [cộng đệm], cộng với kích thước bộ đệm, kích thước được sử dụng và địa chỉ của văn bản thực tế. Một mô hình như vậy sẽ giúp mã có thể vượt qua một chuỗi con tùy ý (không chỉ đuôi) của một chuỗi khác mà không phải sao chép bất cứ điều gì, và sẽ cho phép các phương thức như getsstrcatchấp nhận một cách an toàn bao nhiêu sẽ phù hợp.
supercat

16

Bạn không nên sử dụng getsvì nó không có cách nào để ngăn chặn tràn bộ đệm. Nếu người dùng nhập nhiều dữ liệu hơn mức có thể phù hợp vào bộ đệm của bạn, rất có thể bạn sẽ bị tham nhũng hoặc tệ hơn.

Trên thực tế, ISO đã thực sự đi bước loại bỏ gets khỏi tiêu chuẩn C (kể từ C11, mặc dù nó không được chấp nhận trong C99), do chúng đánh giá mức độ tương thích ngược cao như thế nào, nên là một dấu hiệu cho thấy chức năng đó tệ đến mức nào.

Điều đúng đắn là sử dụng fgets chức năng với stdinxử lý tệp vì bạn có thể giới hạn các ký tự được đọc từ người dùng.

Nhưng điều này cũng có những vấn đề của nó như:

  • các ký tự phụ được nhập bởi người dùng sẽ được chọn trong lần tiếp theo.
  • không có thông báo nhanh rằng người dùng đã nhập quá nhiều dữ liệu.

Cuối cùng, hầu hết mọi lập trình viên C tại một thời điểm nào đó trong sự nghiệp của họ cũng sẽ viết một trình bao bọc hữu ích hơn fgets. Đây là của tôi:

#include <stdio.h>
#include <string.h>

#define OK       0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
    int ch, extra;

    // Get line with buffer overrun protection.
    if (prmpt != NULL) {
        printf ("%s", prmpt);
        fflush (stdout);
    }
    if (fgets (buff, sz, stdin) == NULL)
        return NO_INPUT;

    // If it was too long, there'll be no newline. In that case, we flush
    // to end of line so that excess doesn't affect the next call.
    if (buff[strlen(buff)-1] != '\n') {
        extra = 0;
        while (((ch = getchar()) != '\n') && (ch != EOF))
            extra = 1;
        return (extra == 1) ? TOO_LONG : OK;
    }

    // Otherwise remove newline and give string back to caller.
    buff[strlen(buff)-1] = '\0';
    return OK;
}

với một số mã kiểm tra:

// Test program for getLine().

int main (void) {
    int rc;
    char buff[10];

    rc = getLine ("Enter string> ", buff, sizeof(buff));
    if (rc == NO_INPUT) {
        printf ("No input\n");
        return 1;
    }

    if (rc == TOO_LONG) {
        printf ("Input too long\n");
        return 1;
    }

    printf ("OK [%s]\n", buff);

    return 0;
}

Nó cung cấp sự bảo vệ tương tự như fgets trong đó nó ngăn chặn tràn bộ đệm nhưng nó cũng thông báo cho người gọi về những gì đã xảy ra và xóa các ký tự thừa để chúng không ảnh hưởng đến hoạt động đầu vào tiếp theo của bạn.

Vui lòng sử dụng nó như bạn muốn, sau đây tôi sẽ phát hành nó theo giấy phép "làm những gì bạn rất muốn" :-)


Trên thực tế, tiêu chuẩn C99 ban đầu không phản đối rõ ràng gets()trong phần 7.19.7.7, trong đó nó được xác định hoặc trong phần 7.26.9 Hướng thư viện tương lai và phần phụ cho <stdio.h>. Thậm chí không có chú thích nào về việc nó nguy hiểm. (Có nói rằng, tôi thấy "Nó bị phản đối trong ISO / IEC 9899: 1999 / Cor.3: 2007 (E))" trong câu trả lời của Yu Hao ) Nhưng C11 đã loại bỏ nó khỏi tiêu chuẩn - và không phải trước thời gian.!
Jonathan Leffler

int getLine (char *prmpt, char *buff, size_t sz) { ... if (fgets (buff, sz, stdin) == NULL)ẩn size_tđể intchuyển đổi sz. sz > INT_MAX || sz < 2sẽ bắt các giá trị lạ của sz.
chux - Phục hồi Monica

if (buff[strlen(buff)-1] != '\n') {là một hacker khai thác khi nhân vật đầu tiên của người dùng xấu được nhập vào có thể là một nhân vật null được nhúng kết xuất buff[strlen(buff)-1]UB. while (((ch = getchar())...có vấn đề khi người dùng nhập một ký tự null.
chux - Phục hồi lại

12

fget .

Để đọc từ stdin:

char string[512];

fgets(string, sizeof(string), stdin); /* no buffer overflows here, you're safe! */

6

Bạn không thể xóa các chức năng API mà không phá vỡ API. Nếu bạn muốn, nhiều ứng dụng sẽ không còn biên dịch hoặc chạy nữa.

Đây là lý do mà một tài liệu tham khảo đưa ra:

Đọc một dòng tràn mảng được chỉ ra bởi kết quả s trong hành vi không xác định. Nên sử dụng fgets ().


4

Tôi đã đọc gần đây, trong một bài đăng USENETcomp.lang.c , gets()đang bị xóa khỏi Tiêu chuẩn. WOOHOO

Bạn sẽ rất vui khi biết rằng ủy ban vừa bỏ phiếu (nhất trí, như hóa ra) để loại bỏ get () khỏi dự thảo.


3
Thật tuyệt vời khi nó được gỡ bỏ khỏi tiêu chuẩn. Tuy nhiên, hầu hết các triển khai sẽ cung cấp cho nó như một 'phần mở rộng không chuẩn' trong ít nhất 20 năm tới, vì tính tương thích ngược.
Jonathan Leffler

1
Đúng, đúng, nhưng khi bạn biên dịch với gcc -std=c2012 -pedantic ...got () sẽ không vượt qua được. (Tôi vừa tạo -stdtham số)
pmg

4

Trong C11 (ISO / IEC 9899: 201x), gets()đã bị xóa. (Nó không được chấp nhận trong ISO / IEC 9899: 1999 / Cor.3: 2007 (E))

Ngoài ra fgets(), C11 còn giới thiệu một giải pháp thay thế an toàn mới gets_s():

C11 K.3.5.4.1 gets_sChức năng

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
char *gets_s(char *s, rsize_t n);

Tuy nhiên, trong phần Thực hành khuyến nghị , fgets()vẫn được ưu tiên.

Các fgetschức năng cho phép các chương trình đúng như các văn bản một cách an toàn đường dây quá trình đầu vào quá dài để lưu trữ trong mảng kết quả. Nói chung, điều này đòi hỏi người gọi fgetsphải chú ý đến sự hiện diện hoặc vắng mặt của một ký tự dòng mới trong mảng kết quả. Cân nhắc sử dụng fgets(cùng với bất kỳ xử lý cần thiết nào dựa trên các ký tự dòng mới) thay vì gets_s.


3

gets()là nguy hiểm vì người dùng có thể làm hỏng chương trình bằng cách gõ quá nhiều vào dấu nhắc. Nó không thể phát hiện hết bộ nhớ khả dụng, vì vậy nếu bạn phân bổ một lượng bộ nhớ quá nhỏ cho mục đích, nó có thể gây ra lỗi seg và sự cố. Đôi khi, dường như rất khó có khả năng người dùng sẽ gõ 1000 chữ cái vào một dấu nhắc có nghĩa là tên của một người, nhưng là lập trình viên, chúng ta cần phải làm cho chương trình của mình chống đạn. (nó cũng có thể là một rủi ro bảo mật nếu người dùng có thể làm hỏng chương trình hệ thống bằng cách gửi quá nhiều dữ liệu).

fgets() cho phép bạn chỉ định có bao nhiêu ký tự được lấy ra khỏi bộ đệm đầu vào tiêu chuẩn, vì vậy chúng không tràn ngập biến.


Lưu ý rằng mối nguy hiểm thực sự không nằm ở việc có thể làm sập chương trình của bạn, mà là có thể khiến nó chạy mã tùy ý . (Nói chung, khai thác hành vi không xác định .)
Tanzania87

2

Tôi muốn gửi lời mời tha thiết đến bất kỳ người bảo trì thư viện C nào ngoài đó vẫn bao gồm getstrong thư viện của họ "chỉ trong trường hợp bất kỳ ai vẫn phụ thuộc vào nó": Vui lòng thay thế triển khai của bạn bằng tương đương với

char *gets(char *str)
{
    strcpy(str, "Never use gets!");
    return str;
}

Điều này sẽ giúp đảm bảo không ai còn phụ thuộc vào nó. Cảm ơn bạn.


2

Hàm C nhận được là nguy hiểm và là một sai lầm rất tốn kém. Tony Hoare đã độc thân nhắc đến nó trong bài nói chuyện của mình "Tài liệu tham khảo Null: Sai lầm tỷ đô":

http://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare

Toàn bộ giờ là đáng xem nhưng cho ý kiến ​​của anh ấy xem từ 30 phút trở đi với sự chỉ trích cụ thể khoảng 39 phút.

Hy vọng rằng điều này sẽ kích thích sự thèm ăn của bạn cho toàn bộ cuộc nói chuyện, điều này thu hút sự chú ý về cách chúng ta cần bằng chứng chính xác hơn trong ngôn ngữ và cách các nhà thiết kế ngôn ngữ nên đổ lỗi cho các lỗi trong ngôn ngữ của họ chứ không phải lập trình viên. Đây dường như là toàn bộ lý do đáng ngờ cho các nhà thiết kế ngôn ngữ xấu để đổ lỗi cho các lập trình viên trong chiêu bài 'tự do lập trình viên'.

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.