Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C++

Khai báo lại biến toàn cục (Redeclaration) trong C

Trong C, việc khai báo lại (redeclaration) biến phụ thuộc vào liên kết (linkage) và khởi tạo. Biến cục bộ (local) không cho phép khai báo lại, biến toàn cục (global) cho phép trong một số trường hợp.

Biến cục bộ (Local) - KHÔNG được khai báo lại


int main() {
    int a;
    int a = 50;  // LỖI: redeclaration of 'a' with no linkage
    return 0;
}

Biến toàn cục (Global) - Có thể khai báo lại (tentative definition)

Trường hợp 1: Khai báo không khởi tạo, sau đó định nghĩa


#include <stdio.h>

int a;        // Tentative definition (khai báo thử)
int a = 50;   // Định nghĩa thực sự + khởi tạo

int main() {
    printf("a = %d\n", a);  // 50
}

Trường hợp 2: Nhiều khai báo không khởi tạo (Tentative definitions)


int a;   // OK
int a;   // OK - cùng một tentative definition
int a;   // OK

int main() { }

Trường hợp 3: Hai lần KHỞI TẠO (initialization) - LỖI


int a = 10;  // Định nghĩa + khởi tạo
int a = 50;  // LỖI: redefinition of 'a'

Kết quả

[Error] redefinition of 'a'

Quy tắc tóm tắt (C Standard)

Trường hợpKết quả
Nhiều extern int a;✅ OK (khai báo external)
Nhiều int a; (không init)✅ OK (tentative definition - gộp thành 1)
int a; rồi int a = 10;✅ OK (khai báo rồi định nghĩa)
int a = 10; rồi int a = 20;❌ LỖI (nhiều định nghĩa có khởi tạo)
int a = 10; trong 2 file .c❌ LỖI link (multiple definition)

Best Practice

  • File header (.h): Chỉ khai báo extern int a;
  • File nguồn (.c): Định nghĩa duy nhất int a = 0;
  • Tránh tentative definition - không rõ ràng

Ví dụ chuẩn multi-file


// globals.h
#ifndef GLOBALS_H
#define GLOBALS_H
extern int g_counter;  // Chỉ khai báo
#endif

// globals.c
#include "globals.h"
int g_counter = 0;  // Định nghĩa duy nhất

// main.c
#include "globals.h"
#include <stdio.h>

int main() {
    g_counter++;
    printf("%d\n", g_counter);
}

C++: One Definition Rule (ODR)

C++ nghiêm ngặt hơn: Mọi biến/ hàm phải có duy nhất một định nghĩa trong toàn chương trình. inline variable (C++17) cho phép định nghĩa trong header.