2011-01-01 28 views
10

Một người bạn của tôi gửi mã này với tôi, nói rằng nó không hoạt động như mong đợi:đầu ra không mong đợi từ chương trình sắp xếp nổi bọt với MSVC vs TCC

#include<stdio.h> 

void main() 
{ 
    int a [10] ={23, 100, 20, 30, 25, 45, 40, 55, 43, 42}; 
    int sizeOfInput = sizeof(a)/sizeof(int); 
    int b, outer, inner, c; 
    printf("Size is : %d \n", sizeOfInput); 

    printf("Values before bubble sort are : \n"); 
    for (b = 0; b &lt; sizeOfInput; b++) 
     printf("%d\n", a[b]); 

    printf("End of values before bubble sort... \n"); 

    for (outer = sizeOfInput; outer > 0; outer--) 
    { 
     for ( inner = 0 ; inner < outer ; inner++) 
     { 
     printf ("Comparing positions: %d and %d\n",inner,inner+1); 
     if (a[inner] > a[inner + 1]) 
     { 
       int tmp = a[inner]; 
       a[inner] = a [inner+1]; 
      a[inner+1] = tmp; 
      } 
     } 
     printf ("Bubble sort total array size after inner loop is %d :\n",sizeOfInput); 
     printf ("Bubble sort sizeOfInput after inner loop is %d :\n",sizeOfInput); 
    } 
    printf ("Bubble sort total array size at the end is %d :\n",sizeOfInput); 
    for (c = 0 ; c < sizeOfInput; c++) 
     printf("Element: %d\n", a[c]); 
} 

Tôi đang sử dụng Micosoft Visual Studio lệnh Công cụ Line để biên dịch nó trên máy Windows XP. cl /EHsc bubblesort01.c

Bạn tôi nhận được kết quả chính xác trên máy khủng long (mã được biên soạn bằng TCC tại đó).
Sản lượng của tôi không mong muốn. Các mảng bí ẩn phát triển về kích thước, ở giữa.

Nếu bạn thay đổi mã để biến sizeOfInput được đổi thành sizeOfInputt, nó sẽ cho kết quả mong đợi!

Tìm kiếm được thực hiện tại Microsoft Visual C++ Developer Center không cung cấp bất kỳ kết quả nào cho "sizeOfInput".

Tôi không phải là chuyên gia C/C++, và tò mò muốn tìm hiểu lý do tại sao điều này xảy ra - bất kỳ chuyên gia C/C++ nào có thể "làm sáng tỏ" về điều này?
Lưu ý không liên quan: Tôi đã nghiêm túc nghĩ đến việc viết lại toàn bộ mã để sử dụng quicksort hoặc sắp xếp hợp nhất trước khi đăng nó ở đây. Nhưng, sau khi tất cả, nó không phải là Stooge sắp xếp ...

Chỉnh sửa: Tôi biết mã không đúng (nó đọc ngoài phần tử cuối), nhưng tôi tò mò tại sao tên biến tạo nên sự khác biệt.

+0

Cảm ơn bạn đã chỉnh sửa nhưng chỉ nhận thấy rằng nó đã làm sai các thẻ > và < (>. <). – crnlx

Trả lời

27

Giống như interjay's answer mentioned, sau khi bạn nhận được hành vi không xác định, tất cả các phiên cược sẽ bị tắt. Tuy nhiên, khi bạn nói rằng chỉ đổi tên biến đã thay đổi hành vi của chương trình, tôi đã tò mò về những gì đang diễn ra (không xác định hay không). Trước tiên, tôi không tin rằng đổi tên biến sẽ thay đổi đầu ra của trình biên dịch (tất cả những thứ khác bằng nhau), nhưng chắc chắn - khi tôi thử nó, tôi đã ngạc nhiên khi thấy chính xác những gì bạn mô tả.

Vì vậy, tôi đã có trình biên dịch kết xuất lắp ráp cho mã mà nó đã tạo cho mỗi phiên bản của tệp nguồn và chạy so sánh.Đây là những gì tôi tìm thấy trong các mô tả các trình biên dịch của nó như thế nào đã được đặt ra các biến địa phương:

***** test.sizeOfInput.cod 
    _c$ = -56     ; size = 4 
    _b$ = -52     ; size = 4 
    _inner$ = -48    ; size = 4 
    _a$ = -44     ; size = 40 
>>> _sizeOfInput$ = -4   ; size = 4 
    _main PROC 
    ***** test.sizeOfInputt.cod 
    _c$ = -56     ; size = 4 
>>> _sizeOfInputt$ = -52   ; size = 4 
    _b$ = -48     ; size = 4 
    _inner$ = -44    ; size = 4 
    _a$ = -40     ; size = 40 
    _main PROC 
    ***** 

Những gì bạn sẽ nhận thấy là khi biến được đặt tên sizeOfInput, ông biên dịch nơi nó ở một địa chỉ cao hơn so với mảng a (chỉ cần qua cuối mảng), và khi biến được đặt tên là sizeOfInputt nó đặt nó ở một địa chỉ thấp hơn mảng a thay vì chỉ qua cuối mảng. Điều đó có nghĩa là trong bản dựng có biến có tên là sizeOfInput, hành vi không xác định xảy ra khi bạn sửa đổi a[10] đang thay đổi giá trị sizeOfInput. Trong bản dựng sử dụng tên sizeOfInputt, vì biến đó không nằm ở cuối mảng, việc ghi vào a[10] sẽ khắc phục sự cố khác.

Tại sao trình biên dịch sẽ đặt ra các biến khác nhau khi tên của một thay đổi theo một cách rõ ràng không đáng kể - tôi không có ý tưởng. Nhưng đây là một ví dụ tốt về lý do tại sao bạn không nên dựa vào cách bố trí các biến cục bộ (hoặc nhiều biến bất kỳ, mặc dù bạn có thể dựa vào thứ tự bố cục của các phần tử struct), và tại sao khi nói đến không xác định hành vi, "nó hoạt động trên máy của tôi" không cắt nó như là bằng chứng cho thấy một cái gì đó hoạt động.

+0

Michael, điều này sẽ giúp! Đây là những gì tôi đang tìm kiếm. Chấp nhận câu trả lời của bạn. Cảm ơn bạn đã dành thời gian nghiên cứu về điều này. – crnlx

+8

Có lẽ tất cả các biến được đưa vào một số dạng bản đồ băm và băm của 'sizeOfInput' và' sizeOfInputt' đơn giản là khác nhau. –

6

Mã của bạn đọc qua phần cuối của mảng. Giá trị tối đa là outer là 10 và giá trị tối đa là inner là 9, vì vậy a[inner+1] sẽ đọc a[10]. Điều này sẽ cung cấp cho bạn undefined behavior, điều này giải thích tại sao các trình biên dịch khác nhau cho kết quả khác nhau.

Đối với tên biến tạo sự khác biệt: Có thể không. Có thể nếu bạn chạy cùng một mã hai lần (sử dụng cùng tên biến), bạn sẽ nhận được các kết quả khác nhau. Về cơ bản, khi gọi hành vi không xác định, bạn không thể chắc chắn về bất cứ điều gì mà chương trình của bạn sẽ làm, vì vậy tốt nhất là không nên thử và tìm ý nghĩa trong những thứ như tên biến.

Cũng có khả năng tên biến sẽ tạo sự khác biệt. Điều đó phụ thuộc vào việc thực hiện trình biên dịch: Ví dụ, bằng cách sử dụng một tên biến khác nhau có thể làm cho trình biên dịch tổ chức bộ nhớ khác nhau bằng cách nào đó, mà có thể gây ra các chương trình để bahave khác nhau. Tôi nghĩ rằng hầu hết các trình biên dịch sẽ xuất ra cùng một mã nếu bạn thay đổi tên biến mặc dù, vì vậy nó có lẽ chỉ là một vấn đề của may mắn.

+0

interjay: Cảm ơn, tôi đã cập nhật bài đăng của mình. Tôi biết mã đọc một phần tử nữa - nó rõ ràng từ đầu ra. Tôi bối rối về tên của biến làm nên sự khác biệt như vậy. – crnlx

+0

@interjay: Thấy cập nhật của bạn: không, nếu tôi đặt tên biến là một cái gì đó khác, nó biên dịch và cung cấp cho tôi câu trả lời đúng ngay từ lần đầu tiên. Ngoài ra, biên dịch lại với "sizeOfInput" đã không tạo ra bất kỳ sự khác biệt nào. – crnlx

+0

@Sujith: Ngay cả khi đó là sự thật, nó gần như không thể nói chắc chắn lý do tại sao nó xảy ra mà không kiểm tra mã nguồn của trình biên dịch. Tôi đã thực hiện một chỉnh sửa khác để đưa ra một ví dụ. – interjay

1

Michael Burr's reply cho thấy một hành vi thú vị của trình biên dịch. Nhưng tôi vẫn nghi ngờ tên biến cục bộ có thể ảnh hưởng đến bố cục của nó trong ngăn xếp cho bản ghi hoạt động của hàm.

Tôi đang sử dụng VC++ 2013 với dòng lệnh ở trên (cl.exe/EHsc progam.cpp) và không thể repro nó - thay đổi tên biến không thay đổi hành vi của chương trình, thay vào đó kết quả tốt và một số chạy sụp đổ).

Lý do cho sự cố ngẫu nhiên ở trên là __security_cookie được lưu trữ trực tiếp ở trên (địa chỉ lớn hơn) mảng a và được định nghĩa là mảng số nguyên, kết quả sẽ phụ thuộc vào bit dấu (diễn giải sai) của giá trị của __security_cookie. Nếu nó là một số nguyên dương lớn hơn 100, nó vẫn là giá trị lớn nhất trong mảng a, do đó sắp xếp sẽ không chuyển nó sang vị trí khác, sau đó kiểm tra (__security_check_cookie) ở cuối hàm sẽ không sao. Nếu nó nhỏ hơn 100 hoặc số nguyên âm, nó sẽ được chuyển sang phần tử thấp hơn trong mảng sau khi sắp xếp để báo cáo lỗi __security_check_cookie. Điều này có nghĩa là hành vi của chương trình phụ thuộc vào giá trị được tạo ngẫu nhiên cho __security_cookie.

Tôi đã thay đổi chương trình thử nghiệm ban đầu thành bên dưới để dễ dàng kiểm tra. Tôi cũng mở rộng đầu ra để bao gồm phần tử off-by-one (arrayLen + 1) và chúng tôi có thể dự đoán hành vi dựa trên giá trị ban đầu trong phần tử sau mảng được xác định a.

#include<stdio.h> 
#define arrayLen sizeOfInputt 

void main() 
{ 
    int a [10] ={23, 100, 20, 30, 25, 45, 40, 55, 43, 42}; 
    int arrayLen = sizeof(a)/sizeof(int); 
    int b, outer, inner, c; 
    printf("Size is : %d \n", arrayLen); 

    printf("Values before bubble sort are : \n"); 
    for (b = 0; b < arrayLen + 1; b++) 
     printf("%d\n", a[b]); 

    printf("End of values before bubble sort... \n"); 

    for (outer = arrayLen; outer > 0; outer--) 
    { 
     for ( inner = 0 ; inner < outer ; inner++) 
     { 
     printf ("Comparing positions: %d and %d\n",inner,inner+1); 
     if (a[inner] > a[inner + 1]) 
     { 
       int tmp = a[inner]; 
       a[inner] = a [inner+1]; 
      a[inner+1] = tmp; 
      } 
     } 
     printf ("Bubble sort total array size after inner loop is %d :\n",arrayLen); 
     printf ("Bubble sort arrayLen after inner loop is %d :\n",arrayLen); 
    } 
    printf ("Bubble sort total array size at the end is %d :\n",arrayLen); 
    for (c = 0 ; c < arrayLen; c++) 
     printf("Element: %d\n", a[c]); 
} 
Các vấn đề liên quan