thắc mắc Tại sao chương trình không báo lỗi khi khai báo trùng tên biến vậy các cậu?

Mình không hiểu tại sao chương trình không báo lỗi. Lần in "n" thì lần 1 thì nó in ra n=5, lần in 2 thì nó lại ra giá trị khác. 108856, (nó lấy biến n mới khai báo cục bộ, vậy là có 2 biến tên n mà chương trình ko báo lỗi).

C:
#include<stdio.h>

int n=5;

void main(){
    int x, y; //biến cục bộ trong hàm main
    x = 5;
    y = 6;

    {
        int x = 4;
        printf("x (in sub block) = %d\n", x);
        y += 1;
    }
    printf("n = %d\n", n);
    printf("x (int main block) = %d\n", x);
    printf("y = %d\n", y);

    int n;
    n=n-y;
    printf("n = %d\n", n);
}
 
Mình không hiểu tại sao chương trình không báo lỗi. Lần in "n" thì lần 1 thì nó in ra n=5, lần in 2 thì nó lại ra giá trị khác. 108856, (nó lấy biến n mới khai báo cục bộ, vậy là có 2 biến tên n mà chương trình ko báo lỗi).

Uh đó là cái dở của thằng C đấy. Còn con số 108856 kìa là con số bất kỳ, nó phụ thuộc vào giá trị bất kỳ của ô nhớ của biến đó lúc khởi tạo. Nó ko clear về 0, biến tạo ra ở đâu trên memory thì lấy luôn giá trị tại đó. Lại 1 cái dở khác…

via theNEXTvoz for iPhone
 
Uh đó là cái dở của thằng C đấy. Còn con số 108856 kìa là con số bất kỳ, nó phụ thuộc vào giá trị bất kỳ của ô nhớ của biến đó lúc khởi tạo. Nó ko clear về 0, biến tạo ra ở đâu trên memory thì lấy luôn giá trị tại đó. Lại 1 cái dở khác…

via theNEXTvoz for iPhone
Không báo lỗi vì biến n thứ 2 nằm trong scope cục bộ hơn.
Vậy là thằng trình biên dịch cùi phải không các cậu? Nếu cùng tên thì trình dịch nó lấy tên biến khai báo sau cùng để sử dụng.
 
Vậy là thằng trình biên dịch cùi phải không các cậu? Nếu cùng tên thì trình dịch nó lấy tên biến khai báo sau cùng để sử dụng.
Dùng trình biên dịch nào? VC++ hay GCC? Có biết hết các switch của nó chưa? Compile bằng lệnh như thế nào vậy? Hay là không biết gõ lệnh nên dùng chức năng của IDE?

Chưa gì đã phán trình biên dịch của người ta cùi rồi.
 
Dùng trình biên dịch nào? VC++ hay GCC? Có biết hết các switch của nó chưa? Compile bằng lệnh như thế nào vậy? Hay là không biết gõ lệnh nên dùng chức năng của IDE?

Chưa gì đã phán trình biên dịch của người ta cùi rồi.
Đái dầm đổ tại chim. Chỉ có cái quy định về scope của nó thôi cũng không chịu tìm hiểu xong rồi đi chê trình biên dịch của người ta cùi.
Mình thấy nó hợp lí. Không có gì cùi cả.
Tôi đang hỏi mà? Vậy cuối cùng là dùng C thì có cách nào cho nó báo lỗi khi trùng tên biến không?

Ps/ Tôi dùng Code Block.
 
Last edited:
2 biến n này nằm ở 2 vùng nhớ khác nhau nên biên dịch ko xảy ra lỗi phải k bác
Thằng đầu là global scope tạo ở heap, thằng sau là local tạo ở stack, thằng global ở C khi ko khởi tạo giá trị thì mặc định = 0, thằng local ko khởi tạo thì mặc định là giá trị undefined value.
 
Tôi đang hỏi mà? Vậy cuối cùng là dùng C thì có cách nào cho nó báo lỗi khi trùng tên biến không?

Ps/ Tôi dùng Code Block.
CodeBlocks thì vào Build options của project chọn hết các switch kiểm tra lỗi của nó đi. Không biết switch nào nghĩa gì thì tra Google. Tự học đi. Hỏi nhiều quá cứ ngồi đợi trả lời nên chẳng học được bao nhiêu.
 
2 biến n này nằm ở 2 vùng nhớ khác nhau nên biên dịch ko xảy ra lỗi phải k bác
Đúng rồi. Kể cả chung vùng nhớ nhưng khác bao đóng {} thì 2 biến trùng tên vẫn ok. Khi hàm được gọi đến thì các biến sẽ push lên stack, hết bao đóng là thoát khỏi stack frame, chuyển sang stack frame mới.
 
Last edited:
Đúng rồi. Kể cả chung vùng nhớ nhưng khác bao đóng {} thì 2 biến trùng tên vẫn ok. Khi hàm được gọi đến thì các biến sẽ push lên stack, hết bao đóng là thoát khỏi stack frame, chuyển sang stack frame mới.
Từ ngữ chuyên ngành khó hiểu quá. Tôi tay ngang đọc tài liệu chỉ biết rằng C là ngôn ngữ curly brace, scope của nó là dựa vào dấu ngoặc {}
 
Thằng đầu là global scope tạo ở heap, thằng sau là local tạo ở stack, thằng global ở C khi ko khởi tạo giá trị thì mặc định = 0, thằng local ko khởi tạo thì mặc định là giá trị undefined value.
E nhớ là heap chỉ dùng cho cấp phát động, hay là do biến global ko thuộc function frame nào nên nó được lưu trong heap hả bác
 
E nhớ là heap chỉ dùng cho cấp phát động, hay là do biến global ko thuộc function frame nào nên nó được lưu trong heap hả bác
Nó là biến cho tất cả bọn khác sài đc nên phải đc cấp ở heap, đó là logic về phạm vi biến thôi :D Nếu bác tìm hiểu thêm về cách 1 function nó đc gọi, các data trong function đó đc load vào vùng stack, hủy khi nào thì bác sẽ tự trả lời đc hết mấy cái liên quan đến local, global này :D
 
Nó là biến cho tất cả bọn khác sài đc nên phải đc cấp ở heap, đó là logic về phạm vi biến thôi :D Nếu bác tìm hiểu thêm về cách 1 function nó đc gọi, các data trong function đó đc load vào vùng stack, hủy khi nào thì bác sẽ tự trả lời đc hết mấy cái liên quan đến local, global này :D
Mình hiểu cái golbal này. Nhưng ý nói cái trùng tên ý. Nếu biến local trùng tên thì nó ưu tiên dùng thằng local, ko có thì nó mới dunhf global. Nó báo lỗi hay cảnh báo một tiếng thì đỡ nhầm lẫn đặt lộn tên biến.
 
Đúng rồi. Kể cả chung vùng nhớ nhưng khác bao đóng {} thì 2 biến trùng tên vẫn ok. Khi hàm được gọi đến thì các biến sẽ push lên stack, hết bao đóng là thoát khỏi stack frame, chuyển sang stack frame mới.

Không phải lúc nào biến cũng được đưa lên stack.
Nếu vẫn còn thừa thanh ghi thì trình dịch có thể để ngay tại đó luôn. Nhất là loại biến dùng xong rồi vứt.

Ví dụ với ngay chương trình ở #1, khi compile ở chế độ -O2 thì trình dịch hoàn toàn không dùng stack để chứa giá trị các biến:

https://gcc.godbolt.org/z/fMsKj6zsv

Code:
.LC0:
        .string "x (in sub block) = %d\n"
.LC1:
        .string "n = %d\n"
.LC2:
        .string "x (int main block) = %d\n"
.LC3:
        .string "y = %d\n"
main:
        sub     rsp, 8
        mov     esi, 4
        mov     edi, OFFSET FLAT:.LC0
        xor     eax, eax
        call    printf
        mov     esi, DWORD PTR n[rip]
        mov     edi, OFFSET FLAT:.LC1
        xor     eax, eax
        call    printf
        mov     esi, 5
        mov     edi, OFFSET FLAT:.LC2
        xor     eax, eax
        call    printf
        mov     esi, 7
        mov     edi, OFFSET FLAT:.LC3
        xor     eax, eax
        call    printf
        mov     esi, -7
        mov     edi, OFFSET FLAT:.LC1
        xor     eax, eax
        call    printf
        xor     eax, eax
        add     rsp, 8
        ret
n:
        .long   5

Để ý thấy không có chỗ nào trong đoạn code đụng đến thanh ghi stack rsp, trừ đoạn setup frame ở đầu và cuối. Biến lưu vào thanh ghi khác hết.
 
Last edited:
Back
Top