Rumah  >  Artikel  >  pembangunan bahagian belakang  >  #define INC(a) INC(a ?

#define INC(a) INC(a ?

Susan Sarandon
Susan Sarandonasal
2024-10-22 06:10:31478semak imbas

#define INC(a) INC(a ?

Adakah makro ini merosakkan GCC? Baca dan anda akan dapat jawapannya

Matlamat artikel ini adalah untuk memperkenalkan anda kepada dunia makro yang mengagumkan dalam C.

Arahan prapemproses

Dalam C, baris yang bermula dengan # ditafsirkan oleh pengkompil semasa menyusun fail sumber. Ini dipanggil arahan prapemproses. Makro adalah salah satu daripadanya.

Titik sejarah kecil:

Makro bahasa C telah diperkenalkan dengan standard bahasa C yang pertama, dipanggil ANSI C (atau C89),
yang telah diseragamkan oleh American National Standards Institute (ANSI) pada tahun 1989.

Walau bagaimanapun, sebelum penyeragaman ini, makro telah pun menjadi sebahagian daripada bahasa C (atau K&R C) yang digunakan pada tahun 1970-an
Pengkompil C asal, yang dibangunkan oleh Dennis Ritchie untuk sistem pengendalian UNIX, telah pun menyertakan bentuk asas makro melalui prapemproses, membenarkan takrifan dengan #define.

takrifkan

#define SENS_DE_LA_VIE 3.14

/* ... */

printf("%f\n", SENS_DE_LA_VIE);

Define berfungsi dengan mudah untuk difahami: pengkompil menggantikan semua kejadian dalam kod dengan nilai yang ditentukan. Ia berfungsi dengan sintaks berikut #define . Ia adalah satu konvensyen untuk meletakkan nama dalam huruf besar, nilainya adalah pilihan.

Sedikit seperti "Ctrl-f dan ganti".

Mama, makro

Kami boleh menggunakan defines untuk mentakrifkan fungsi yang boleh kami gunakan dalam kod kami.

#define INC(a) a++ 
#define MULTI_LINE(a,b) a = b; \
                        b = 0; 


INC(my_variable); 
MULTI_LINE(my_variable, foobar) 
// Je souligne le fait qu'il peut ne pas y avoir de ';' en fin de ligne 

// Cela donnera  
my_variable++;
my_variable = foobar;
foobar = 0;

Jika atau tidak jika

Kami boleh mengisytiharkan makro secara bersyarat.
Jika nama sudah ditakrifkan maka kami melaksanakan sekeping kod berikut.

#ifdef DEBUG
// Je souligne qu'il est rarement conseillé d'utiliser des printf() en debug
// et que nous avons brisé la règle du nom des macros en MAJ.
#define return printf("(%s:%d)\n", __FUNCTION__, __LINE__);  return
#endif /* ! DEBUG */

int main(void) {
    return 1;
}

Dalam kes ini, saya menggunakan #ifndef, tetapi ia juga wujud:

  • #ifdef
  • #jika
  • #lain
  • #elif
#if (X == 1)
#define Y 2
#elif (X == 2)
#define Y "Ami de la bonne blague, bonjour !"
#else
#define Y NULL
#endif /* ! X */

/* ... */

int main(void) {
    #if (X == 1)
    printf("%d\n", Y);
    #elif (X == 2)
    printf("%s\n", Y);
    #else
    printf("%p\n", Y);
    #endif /* ! X */
}

Kami suka memberi isyarat penamat #jika dengan ulasan pukal. Ini adalah konvensyen yang membolehkan anda menavigasi kod dengan lebih baik.

Makro yang dipratentukan

Anda boleh lihat dalam contoh sebelumnya bahawa saya menggunakan kata kunci __FUNCTION__ dan __LINE__.
Seperti yang anda jangkakan, ini adalah makro yang akan digantikan oleh pengkompil dengan nilai yang betul.

Terdapat senarai makro Pratetap Biasa.

Perhatikan bahawa terdapat apa yang dipanggil makro khusus Sistem.

Senarai kecil yang tidak lengkap:

  • __TARIKH__: 14 Jan 2012
  • __GNUC__: Versi utama GCC
  • __MASA__: 15:12:18
  • __INCLUDE_LEVEL__: Kedalaman termasuk bermula dengan 0
  • __BASE_FILE__: Nama fail semasa

Menuju infiniti dan melampaui hujah

#define SENS_DE_LA_VIE 3.14

/* ... */

printf("%f\n", SENS_DE_LA_VIE);

Di sini, kita dapat melihat bahawa kita menjana makro variadik, terutamanya berguna apabila membuat log.
(Walaupun bukan idea yang baik untuk membuat log dengan printfs.)

X-Makro

Untuk ini, kita perlu mencipta fail luaran, sering dinamakan *.def walaupun tiada konvensyen.

#define INC(a) a++ 
#define MULTI_LINE(a,b) a = b; \
                        b = 0; 


INC(my_variable); 
MULTI_LINE(my_variable, foobar) 
// Je souligne le fait qu'il peut ne pas y avoir de ';' en fin de ligne 

// Cela donnera  
my_variable++;
my_variable = foobar;
foobar = 0;
#ifdef DEBUG
// Je souligne qu'il est rarement conseillé d'utiliser des printf() en debug
// et que nous avons brisé la règle du nom des macros en MAJ.
#define return printf("(%s:%d)\n", __FUNCTION__, __LINE__);  return
#endif /* ! DEBUG */

int main(void) {
    return 1;
}

Makro jenis ini amat berguna. Saya mesti mengakui bahawa ia jarang ditemui dalam kod sumber, tetapi ia membolehkan anda mengubah suai operasi program tanpa perlu mengubah suai kod sumber. Fakta yang menyeronokkan, ia sering digunakan dalam penciptaan biji. Ia membolehkan anda menjana struktur global seperti IDT dan GDT.

Masalahnya

Perhatian: Penjelasan pantas dahulu, makro ialah alat yang hebat tetapi anda perlu berhati-hati. Anda semestinya tidak boleh menggunakan makro jenis ini:

#if (X == 1)
#define Y 2
#elif (X == 2)
#define Y "Ami de la bonne blague, bonjour !"
#else
#define Y NULL
#endif /* ! X */

/* ... */

int main(void) {
    #if (X == 1)
    printf("%d\n", Y);
    #elif (X == 2)
    printf("%s\n", Y);
    #else
    printf("%p\n", Y);
    #endif /* ! X */
}

Mari kita ambil contoh: MIN(2 5, fibo(25))

Masalah #1

MIN(2 5, fibo(25)) => (2 5 < fibo(25) ? 2 5: fibo(25))

Di sini masalahnya ialah keutamaan pengiraan. Pengkompil terlebih dahulu akan melakukan perbandingan kemudian penambahan, oleh itu 2 (1). Kami membetulkannya dengan menambahkan kurungan menggunakan argumen makro.

// Ici, l'opérateur ## est l'opérateur de concaténation
#define DEBUG_PRNTF(fmt, ...) printf("LOG" ## fmt, __VA_ARGS__);

Memandangkan anda tidak pernah tahu perkara yang pengguna anda akan luluskan sebagai parameter, sentiasa letakkan kurungan pada hujah.

Masalah #2

MIN(2 5, fibo(25)) => (2 5 < fibo(25) ? 2 5: fibo(25))

Kami mendapati bahawa pengkompil membuat penggantian yang bodoh dan jahat, yang bermaksud bahawa kami akan mengira fibo(25) dua kali. Saya akan membiarkan anda bayangkan jika ia adalah pelaksanaan rekursif.

Untuk menyelesaikan masalah ini, kami mengisytiharkan pembolehubah perantaraan sebelum if.

Makro berguna

// color.def
X(NC, "\e[0m", "No Color", 0x000000) 
X(BLACK, "\e[0;30m", "Black", 0x000000) 
X(GRAY, "\e[1;30m", "Gray", 0x808080) 
X(RED, "\e[0;31m", "Red", 0xFF0000) 
X(LIGHT_RED, "\e[1;31m", "Light Red", 0xFF8080) 
X(GREEN, "\e[0;32m", "Green", 0x00FF00) 
X(LIGHT_GREEN, "\e[1;32m", "Light Green", 0x80FF80) 
X(BROWN, "\e[0;33m", "Brown", 0xA52A2A) 
X(YELLOW, "\e[1;33m", "Yellow", 0xFFFF00) 
X(BLUE, "\e[0;34m", "Blue", 0x0000FF) 
X(LIGHT_BLUE, "\e[1;34m", "Light Blue", 0xADD8E6) 
X(PURPLE, "\e[0;35m", "Purple", 0x800080) 
X(LIGHT_PURPLE, "\e[1;35m", "Light Purple", 0xEE82EE) 
X(CYAN, "\e[0;36m", "Cyan", 0x00FFFF) 
X(LIGHT_CYAN, "\e[1;36m", "Light Cyan", 0xE0FFFF) 
X(LIGHT_GRAY, "\e[0;37m", "Light Gray", 0xD3D3D3) 
X(WHITE, "\e[1;37m", "White", 0xFFFFFF)

Di sana kita berseronok

Di sini, ia adalah kod berlebihan semata-mata untuk keseronokan. Saya tidak semestinya menasihati anda untuk menggunakan makro ini dalam kod anda.
Saya hanya berseronok (perkara yang baik dalam hidup).

Kereta percuma

typedef struct {
    const char *name;        
    const char *ansi_code;  
    const char *description;
    unsigned int rgb;      
} Color;

#define X(NAME, ANSI, DESC, RGB) { #NAME, ANSI, DESC, RGB },
Color colors[] = {
    #include "color.def"
};
#undef X

#define X(NAME, ANSI, DESC, RGB) printf("%s (%s) = %s\n", #NAME, DESC, #RGB);
void print_colors() {
    // Bien entendu, on pourrait itérer sur la structure créée mais c'est une illustration
    #include "color.def"
}
#undef X

Saya akan membenarkan anda menguji dengan sedikit -fsanitize=address. Ia benar-benar gila. Kami juga dapat melihat peningkatan pada fungsi auto_free yang mengambil sebagai parameter rentetan aksara nama struktur kami untuk membuat suis.

Dapatkan masa

Fungsi chiller di mana kita hanya mengira masa pelaksanaan fungsi kita. Sangat berguna untuk penanda aras.

#define SENS_DE_LA_VIE 3.14

/* ... */

printf("%f\n", SENS_DE_LA_VIE);

Takrif Ralat

Makro X kecil yang mengambil makro sebagai hujah dan mengembangkannya.

#define INC(a) a++ 
#define MULTI_LINE(a,b) a = b; \
                        b = 0; 


INC(my_variable); 
MULTI_LINE(my_variable, foobar) 
// Je souligne le fait qu'il peut ne pas y avoir de ';' en fin de ligne 

// Cela donnera  
my_variable++;
my_variable = foobar;
foobar = 0;

Penjanaan ujian automatik

Di sini, kami sebenarnya menjana keseluruhan fungsi dengan makro, kerana C tidak mempunyai had. Saya juga?

#ifdef DEBUG
// Je souligne qu'il est rarement conseillé d'utiliser des printf() en debug
// et que nous avons brisé la règle du nom des macros en MAJ.
#define return printf("(%s:%d)\n", __FUNCTION__, __LINE__);  return
#endif /* ! DEBUG */

int main(void) {
    return 1;
}

RTFM

Kini tiba masanya untuk menyelesaikan masalah. Kami melihat banyak perkara yang sangat menarik. Dan jika anda pernah tergoda, anda bebas untuk menemui makro untuk diri sendiri. Masih banyak perkara yang boleh dilihat.
Jadi, kesimpulan: RTFM.

PS: Bagi tajuk, makro bukan rekursif, ia hanya berkembang dengan kedalaman 1 dan dalam kes kami sekarang, GCC akan membuat pengisytiharan_implisit pada INC dan ranap sistem.

Atas ialah kandungan terperinci #define INC(a) INC(a ?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn