2014-09-12 20 views
6

strlen trả về số ký tự đứng trước ký tự null kết thúc. An thực hiện strlen có thể trông như thế này:Strlen có phải là một chuỗi với các giá trị chưa được khởi tạo không xác định hành vi không?

size_t strlen(const char * str) 
{ 
    const char *s; 
    for (s = str; *s; ++s) {} 
    return(s - str); 
} 

thực hiện đặc biệt này dereferences s, nơi s có thể chứa các giá trị không xác định. Nó tương đương với điều này:

int a; 
int* p = &a; 
*p; 

Vì vậy, ví dụ nếu ai đó để làm điều này (gây strlen để đưa ra một sản lượng không chính xác):

char buffer[10]; 
buffer[9] = '\0'; 
strlen(buffer); 

Có hành vi undefined?

+1

@ user2864740 bạn có chắc chắn rằng chuỗi * phải * chứa một số giá trị không? Không phải C cho phép vui vẻ rơi vào một đọc-trước-viết? – kay

Trả lời

2

Gọi hàm chuẩn strlen gây ra hành vi không xác định. DR 451 làm rõ điều này:

chức năng thư viện sẽ triển lãm hành vi undefined khi được sử dụng trên các giá trị không xác định

Đối với một sâu hơn thảo luận see this thread.

+0

Nhận xét của tôi dưới đây đề cập đến việc triển khai áp phích của một hàm strlen. Đồng ý rằng thư viện chuẩn có các ràng buộc hoặc tự do khác. –

+0

buffer [9] là khá xác định ... – Basilevs

+0

@ KC-NH đã cập nhật bài đăng của tôi để làm rõ rằng tôi đang nói về chức năng 'strlen' chuẩn, chứ không phải triển khai thực hiện giả của OP. –

1

Không, đó không phải là hành vi không xác định. Hàm strlen của bạn sẽ dừng trước khi kết thúc bộ đệm. Nếu hàm strlen của bạn tham chiếu buffer [10], thì, yes là undefined.

Chắc chắn đó sẽ là hành vi không mong muốn vì hầu hết bộ đệm chứa dữ liệu ngẫu nhiên. "Không xác định" là từ đặc biệt cho những người viết các tiêu chuẩn ngôn ngữ. Nó có nghĩa là bất cứ điều gì có thể xảy ra, bao gồm cả lỗi bộ nhớ hoặc thoát khỏi chương trình. Bởi bất ngờ, tôi có nghĩa là nó chắc chắn không phải những gì các lập trình viên muốn xảy ra. Trên một số lần chạy, kết quả của strlen có thể là 3 hoặc có thể là 10.

0

Có, đó là hành vi không xác định. Từ dự thảo tiêu chuẩn C11, §J.2 "hành vi Không xác định":

Các hành vi là undefined trong các trường hợp sau đây:

...

Giá trị của một đối tượng với thời gian lưu trữ tự động được sử dụng trong khi đó là không xác định.

+2

Mã này không thực sự sử dụng các giá trị không xác định ('buffer' không xác định, nhưng' buffer [0] 'là). Tuy nhiên, 'strlen' sử dụng các giá trị. Ngoài ra, phụ lục này là không quy chuẩn (nó được cho là một loại chỉ số để tìm các trường hợp khác nhau của UB). Văn bản quy phạm chi tiết hơn và có một số ngoại lệ khi sử dụng không xác định không phải là UB. –

+1

Đối tượng không chỉ là "không xác định" nhưng các giá trị chỉ là "không xác định", vì vậy không có gì xấu có thể xảy ra. –

2

Hành vi của biến thể bạn đang hiển thị được xác định rõ trong những trường hợp này.

  • Các byte của mảng chưa được khởi tạo có tất cả các giá trị không xác định, ngoại trừ phần tử thứ 10 mà bạn đặt thành 0.
  • Truy cập giá trị không xác định sẽ chỉ là UB nếu địa chỉ của đối tượng bên dưới sẽ không bao giờ được thực hiện hoặc nếu giá trị là bẫy cho loại tương ứng.
  • Vì đây là mảng và truy cập vào phần tử mảng là thông qua số học con trỏ, trường hợp đầu tiên không có liên quan, tại đây.
  • Bất kỳ giá trị char nào có thể được truy cập mà không có UB, các mệnh đề về biểu diễn bẫy trong tiêu chuẩn loại trừ rõ ràng tất cả các loại ký tự từ đó.
  • Do đó, các giá trị mà bạn đang xử lý chỉ đơn giản là "không xác định".
  • Đọc các giá trị không xác định có thể theo một số thành viên của ủy ban tiêu chuẩn C cho kết quả khác nhau mỗi lần, điều mà một số người gọi là trạng thái "điên rồ". Thuộc tính này không liên quan, ở đây, vì hàm của bạn đọc bất kỳ giá trị nào như vậy nhiều nhất một lần.
  • Vì vậy, quyền truy cập của bạn vào các phần tử mảng cung cấp cho bạn bất kỳ giá trị char tùy ý nhưng hợp lệ.
  • Bạn chắc chắn rằng vòng kết nối for của bạn dừng lại ở vị trí mới nhất 9, vì vậy bạn sẽ không vượt quá mảng của mình.

Vì vậy, không có thứ "xấu" nào ngoài hiển thị có thể xảy ra nếu bạn sử dụng phiên bản chức năng cụ thể của mình. Nhưng có một cuộc gọi hàm tạo ra các kết quả không xác định chắc chắn là không có gì bạn muốn thấy trong mã thực. Một cái gì đó như thế này ở đây dẫn đến lỗi rất tinh tế, và bạn nên tránh nó bằng mọi cách.

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