【c/c++】c和cpp混合编译

这篇具有很好参考价值的文章主要介绍了【c/c++】c和cpp混合编译。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

c和cpp混合编译

#ifdef __cplusplus
extern "C" {
#endif

extern int test(int, int);

#ifdef __cplusplus
}
#endif

在这段代码中,#ifdef __cplusplus 和 #endif 之间的代码是为了在 C++ 中使用 C 语言的函数声明和定义时,确保编译器正确地处理 C 和 C++ 之间的语法差异。这是因为 C 和 C++ 有一些不同之处,包括函数名的重载、类型转换等。

在这段代码中,extern “C” 是一个 C++ 的特性,它告诉编译器要按照 C 的方式来处理其中的函数。具体来说:

#ifdef __cplusplus:这个条件编译指令检查是否正在编译 C++ 代码。__cplusplus 是一个宏,当编译器编译 C++ 代码时,它会被定义。因此,如果代码正在编译为 C++,那么这个条件成立。

extern “C” {:如果正在编译为 C++,那么 extern “C” 会告诉编译器,接下来的代码块中的函数应该以 C 的方式进行链接,而不是 C++ 的方式。这是因为在 C++ 中,函数名可以发生函数重载(同一个函数名可以有不同的参数列表),而在 C 中没有这个概念。因此,通过将函数声明包裹在 extern “C” 中,可以确保它们以 C 的方式进行链接,这样cpp代码可以与纯 C 代码一起使用而不会出现问题。

#endif:这是条件编译的结束指令,它用来结束 #ifdef __cplusplus 开始的条件编译块。如果不是在编译 C++ 代码,这个块中的代码会被忽略。

总之,这段代码的作用是确保在 C++ 中使用 C 语言函数时,编译器不会将其与 C++ 的语法特性混淆,从而确保代码的正确性。这在涉及到与 C 代码互操作的情况下非常有用,因为 C++ 和 C 之间存在一些重要的差异。

C++编译的时候会改函数的名字

C++ 在编译时会对函数的名字进行改编,这个过程被称为名称修饰(Name Mangling)。这是因为 C++ 允许函数重载,也就是说,可以定义多个同名函数,只要它们的参数列表不同。为了区分这些重载函数,C++ 编译器会对函数名进行修饰,将参数信息包含在函数名中,从而创建唯一的函数标识符。

举例来说,如果有以下两个函数:

int add(int a, int b);
double add(double a, double b);

在编译时,C++ 编译器会对这两个函数的名称进行改编,以便区分它们。名称修饰的结果可能会变成类似于 _Z3addii 和 _Z3adddd 这样的标识符,具体的修饰规则取决于编译器和平台。

然而,C 语言不支持函数重载,因此在 C 中不需要进行名称修饰。函数的名称在 C 中保持原样。这就是为什么在 C++ 中与 C 代码进行交互时需要使用 extern “C” 声明来告诉编译器不要对函数名称进行修饰,以便正确链接到 C 代码。

所以,为了确保 C++ 代码与 C 代码正确地进行交互,需要使用 extern “C” 声明,以防止 C++ 编译器对函数名称进行修饰,从而保持与 C 代码的兼容性。这样可以确保 C++ 代码能够与不进行名称修饰的 C 函数正确匹配。

从汇编的角度详细解释

名称修饰(Name Mangling)是一个高级语言(如C++)到汇编语言层面的概念,它涉及到函数和类的名称在汇编代码中的表示方式。不同编译器和平台可能会有不同的名称修饰规则,下面我将通过一个简单的例子来说明这个概念。

首先,让我们看一个简单的C++代码(extern “C”):

#include <iostream>
extern "C"
{
int add(int a, int b) {
    return a + b;
}
}
int main() {
    int result = add(3, 4);
    std::cout << result << std::endl;
    return 0;
}

接下来,我们将使用 g++ 编译这段代码,并通过汇编工具查看生成的汇编代码。可以使用以下命令来编译代码并生成汇编文件:

g++ -S -o example.s example.cpp

上述命令中,-S 选项告诉 g++ 生成汇编代码,并将其输出到 example.s 文件中。现在,让我们查看生成的 example.s 文件:

	.file	"example.cpp"
	.text
	.local	_ZStL8__ioinit
	.comm	_ZStL8__ioinit,1,1
	.globl	add
	.type	add, @function
add:
.LFB1731:
	.cfi_startproc
	endbr64
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movl	%edi, -4(%rbp)
	movl	%esi, -8(%rbp)
	movl	-4(%rbp), %edx
	movl	-8(%rbp), %eax
	addl	%edx, %eax
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE1731:
	.size	add, .-add
	.globl	main
	.type	main, @function
main:
.LFB1732:
	.cfi_startproc
	endbr64
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	subq	$16, %rsp
	movl	$4, %esi
	movl	$3, %edi
	call	add
	movl	%eax, -4(%rbp)
	movl	-4(%rbp), %eax
	movl	%eax, %esi
	leaq	_ZSt4cout(%rip), %rax
	movq	%rax, %rdi
	call	_ZNSolsEi@PLT
	movq	_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GOTPCREL(%rip), %rdx
	movq	%rdx, %rsi
	movq	%rax, %rdi
	call	_ZNSolsEPFRSoS_E@PLT
	movl	$0, %eax
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE1732:
	.size	main, .-main
	.type	_Z41__static_initialization_and_destruction_0ii, @function
_Z41__static_initialization_and_destruction_0ii:
.LFB2232:
	.cfi_startproc
	endbr64
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	subq	$16, %rsp
	movl	%edi, -4(%rbp)
	movl	%esi, -8(%rbp)
	cmpl	$1, -4(%rbp)
	jne	.L7
	cmpl	$65535, -8(%rbp)
	jne	.L7
	leaq	_ZStL8__ioinit(%rip), %rax
	movq	%rax, %rdi
	call	_ZNSt8ios_base4InitC1Ev@PLT
	leaq	__dso_handle(%rip), %rax
	movq	%rax, %rdx
	leaq	_ZStL8__ioinit(%rip), %rax
	movq	%rax, %rsi
	movq	_ZNSt8ios_base4InitD1Ev@GOTPCREL(%rip), %rax
	movq	%rax, %rdi
	call	__cxa_atexit@PLT
.L7:
	nop
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE2232:
	.size	_Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii
	.type	_GLOBAL__sub_I_add, @function
_GLOBAL__sub_I_add:
.LFB2233:
	.cfi_startproc
	endbr64
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movl	$65535, %esi
	movl	$1, %edi
	call	_Z41__static_initialization_and_destruction_0ii
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE2233:
	.size	_GLOBAL__sub_I_add, .-_GLOBAL__sub_I_add
	.section	.init_array,"aw"
	.align 8
	.quad	_GLOBAL__sub_I_add
	.hidden	__dso_handle
	.ident	"GCC: (Ubuntu 11.3.0-1ubuntu1~22.04.1) 11.3.0"
	.section	.note.GNU-stack,"",@progbits
	.section	.note.gnu.property,"a"
	.align 8
	.long	1f - 0f
	.long	4f - 1f
	.long	5
0:
	.string	"GNU"
1:
	.align 8
	.long	0xc0000002
	.long	3f - 2f
2:
	.long	0x3
3:
	.align 8
4:

在上述汇编代码中,我们关注的是 add函数和 main 函数。注意以下几点:

  1. .globl add表示 add 函数是全局可见的,这是因为我们在 main 函数中调用了它。

  2. .type add, @function 表示 add 函数是一个函数。

  3. .size add, .-add 给出了 add 函数的大小。

  4. add: 标识了 add 函数的入口点。

  5. call add是在 main 函数中调用 add 函数的指令。

从这个例子中,可以看到函数 add 在汇编代码中的名称没有发生明显的变化,因为这是一个普通的 C 函数。名称修饰通常在涉及到函数重载、命名空间、类等高级语言特性时变得更加复杂。不同的编译器和平台可能会使用不同的规则来进行名称修饰,所以具体的名称修饰方式会有所不同。

下面是不使用extern "C"的汇编代码:

#include <iostream>

int add(int a, int b) {
    return a + b;
}

int main() {
    int result = add(3, 4);
    std::cout << result << std::endl;
    return 0;
}

再次使用以下命令来编译代码并生成汇编文件:

g++ -S -o example.s example.cpp

查看生成的 example.s 文件:

	.file	"example.cpp"
   .text
   .local	_ZStL8__ioinit
   .comm	_ZStL8__ioinit,1,1
   .globl	_Z3addii
   .type	_Z3addii, @function
_Z3addii:
.LFB1731:
   .cfi_startproc
   endbr64
   pushq	%rbp
   .cfi_def_cfa_offset 16
   .cfi_offset 6, -16
   movq	%rsp, %rbp
   .cfi_def_cfa_register 6
   movl	%edi, -4(%rbp)
   movl	%esi, -8(%rbp)
   movl	-4(%rbp), %edx
   movl	-8(%rbp), %eax
   addl	%edx, %eax
   popq	%rbp
   .cfi_def_cfa 7, 8
   ret
   .cfi_endproc
.LFE1731:
   .size	_Z3addii, .-_Z3addii
   .globl	main
   .type	main, @function
main:
.LFB1732:
   .cfi_startproc
   endbr64
   pushq	%rbp
   .cfi_def_cfa_offset 16
   .cfi_offset 6, -16
   movq	%rsp, %rbp
   .cfi_def_cfa_register 6
   subq	$16, %rsp
   movl	$4, %esi
   movl	$3, %edi
   call	_Z3addii
   movl	%eax, -4(%rbp)
   movl	-4(%rbp), %eax
   movl	%eax, %esi
   leaq	_ZSt4cout(%rip), %rax
   movq	%rax, %rdi
   call	_ZNSolsEi@PLT
   movq	_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GOTPCREL(%rip), %rdx
   movq	%rdx, %rsi
   movq	%rax, %rdi
   call	_ZNSolsEPFRSoS_E@PLT
   movl	$0, %eax
   leave
   .cfi_def_cfa 7, 8
   ret
   .cfi_endproc
.LFE1732:
   .size	main, .-main
   .type	_Z41__static_initialization_and_destruction_0ii, @function
_Z41__static_initialization_and_destruction_0ii:
.LFB2232:
   .cfi_startproc
   endbr64
   pushq	%rbp
   .cfi_def_cfa_offset 16
   .cfi_offset 6, -16
   movq	%rsp, %rbp
   .cfi_def_cfa_register 6
   subq	$16, %rsp
   movl	%edi, -4(%rbp)
   movl	%esi, -8(%rbp)
   cmpl	$1, -4(%rbp)
   jne	.L7
   cmpl	$65535, -8(%rbp)
   jne	.L7
   leaq	_ZStL8__ioinit(%rip), %rax
   movq	%rax, %rdi
   call	_ZNSt8ios_base4InitC1Ev@PLT
   leaq	__dso_handle(%rip), %rax
   movq	%rax, %rdx
   leaq	_ZStL8__ioinit(%rip), %rax
   movq	%rax, %rsi
   movq	_ZNSt8ios_base4InitD1Ev@GOTPCREL(%rip), %rax
   movq	%rax, %rdi
   call	__cxa_atexit@PLT
.L7:
   nop
   leave
   .cfi_def_cfa 7, 8
   ret
   .cfi_endproc
.LFE2232:
   .size	_Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii
   .type	_GLOBAL__sub_I__Z3addii, @function
_GLOBAL__sub_I__Z3addii:
.LFB2233:
   .cfi_startproc
   endbr64
   pushq	%rbp
   .cfi_def_cfa_offset 16
   .cfi_offset 6, -16
   movq	%rsp, %rbp
   .cfi_def_cfa_register 6
   movl	$65535, %esi
   movl	$1, %edi
   call	_Z41__static_initialization_and_destruction_0ii
   popq	%rbp
   .cfi_def_cfa 7, 8
   ret
   .cfi_endproc
.LFE2233:
   .size	_GLOBAL__sub_I__Z3addii, .-_GLOBAL__sub_I__Z3addii
   .section	.init_array,"aw"
   .align 8
   .quad	_GLOBAL__sub_I__Z3addii
   .hidden	__dso_handle
   .ident	"GCC: (Ubuntu 11.3.0-1ubuntu1~22.04.1) 11.3.0"
   .section	.note.GNU-stack,"",@progbits
   .section	.note.gnu.property,"a"
   .align 8
   .long	1f - 0f
   .long	4f - 1f
   .long	5
0:
   .string	"GNU"
1:
   .align 8
   .long	0xc0000002
   .long	3f - 2f
2:
   .long	0x3
3:
   .align 8
4:

要查看真正的名称修饰效果,可以尝试创建一个包含类和函数重载的更复杂的 C++ 示例,并查看生成的汇编代码,以了解不同情况下的名称修饰规则。但需要注意的是,名称修饰通常是编译器的内部实现细节,不同编译器可能会有不同的名称修饰方案。

下面是一个包含类和函数重载的较复杂的 C++ 示例:

#include <iostream>

class Math {
public:
   int add(int a, int b) {
       return a + b;
   }

   double add(double a, double b) {
       return a + b;
   }
};

int main() {
   Math math;
   int intResult = math.add(3, 4);
   double doubleResult = math.add(2.5, 3.7);

   std::cout << "Integer result: " << intResult << std::endl;
   std::cout << "Double result: " << doubleResult << std::endl;

   return 0;
}

在这个示例中,我们定义了一个名为 Math 的类,其中包含了两个 add 函数,一个用于整数相加,另一个用于浮点数相加。这两个函数具有相同的名称,但参数类型不同,这就是函数重载。

接下来,我们编译这个示例并查看生成的汇编代码。使用以下命令来生成汇编文件:

g++ -S -o complex_example.s complex_example.cpp

现在,让我们查看生成的 complex_example.s 文件中与 Math 类和 add 函数相关的部分:

   .file	"complex_example.cpp"
   .text
   .local	_ZStL8__ioinit
   .comm	_ZStL8__ioinit,1,1
   .section	.text._ZN4Math3addEii,"axG",@progbits,_ZN4Math3addEii,comdat
   .align 2
   .weak	_ZN4Math3addEii
   .type	_ZN4Math3addEii, @function
_ZN4Math3addEii:
.LFB1731:
   .cfi_startproc
   endbr64
   pushq	%rbp
   .cfi_def_cfa_offset 16
   .cfi_offset 6, -16
   movq	%rsp, %rbp
   .cfi_def_cfa_register 6
   movq	%rdi, -8(%rbp)
   movl	%esi, -12(%rbp)
   movl	%edx, -16(%rbp)
   movl	-12(%rbp), %edx
   movl	-16(%rbp), %eax
   addl	%edx, %eax
   popq	%rbp
   .cfi_def_cfa 7, 8
   ret
   .cfi_endproc
.LFE1731:
   .size	_ZN4Math3addEii, .-_ZN4Math3addEii
   .section	.text._ZN4Math3addEdd,"axG",@progbits,_ZN4Math3addEdd,comdat
   .align 2
   .weak	_ZN4Math3addEdd
   .type	_ZN4Math3addEdd, @function
_ZN4Math3addEdd:
.LFB1732:
   .cfi_startproc
   endbr64
   pushq	%rbp
   .cfi_def_cfa_offset 16
   .cfi_offset 6, -16
   movq	%rsp, %rbp
   .cfi_def_cfa_register 6
   movq	%rdi, -8(%rbp)
   movsd	%xmm0, -16(%rbp)
   movsd	%xmm1, -24(%rbp)
   movsd	-16(%rbp), %xmm0
   addsd	-24(%rbp), %xmm0
   movq	%xmm0, %rax
   movq	%rax, %xmm0
   popq	%rbp
   .cfi_def_cfa 7, 8
   ret
   .cfi_endproc
.LFE1732:
   .size	_ZN4Math3addEdd, .-_ZN4Math3addEdd
   .section	.rodata
.LC2:
   .string	"Integer result: "
.LC3:
   .string	"Double result: "
   .text
   .globl	main
   .type	main, @function
main:
.LFB1733:
   .cfi_startproc
   endbr64
   pushq	%rbp
   .cfi_def_cfa_offset 16
   .cfi_offset 6, -16
   movq	%rsp, %rbp
   .cfi_def_cfa_register 6
   subq	$32, %rsp
   movq	%fs:40, %rax
   movq	%rax, -8(%rbp)
   xorl	%eax, %eax
   leaq	-21(%rbp), %rax
   movl	$4, %edx
   movl	$3, %esi
   movq	%rax, %rdi
   call	_ZN4Math3addEii
   movl	%eax, -20(%rbp)
   movsd	.LC0(%rip), %xmm0
   movq	.LC1(%rip), %rdx
   leaq	-21(%rbp), %rax
   movapd	%xmm0, %xmm1
   movq	%rdx, %xmm0
   movq	%rax, %rdi
   call	_ZN4Math3addEdd
   movq	%xmm0, %rax
   movq	%rax, -16(%rbp)
   leaq	.LC2(%rip), %rax
   movq	%rax, %rsi
   leaq	_ZSt4cout(%rip), %rax
   movq	%rax, %rdi
   call	_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@PLT
   movq	%rax, %rdx
   movl	-20(%rbp), %eax
   movl	%eax, %esi
   movq	%rdx, %rdi
   call	_ZNSolsEi@PLT
   movq	_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GOTPCREL(%rip), %rdx
   movq	%rdx, %rsi
   movq	%rax, %rdi
   call	_ZNSolsEPFRSoS_E@PLT
   leaq	.LC3(%rip), %rax
   movq	%rax, %rsi
   leaq	_ZSt4cout(%rip), %rax
   movq	%rax, %rdi
   call	_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@PLT
   movq	%rax, %rdx
   movq	-16(%rbp), %rax
   movq	%rax, %xmm0
   movq	%rdx, %rdi
   call	_ZNSolsEd@PLT
   movq	_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GOTPCREL(%rip), %rdx
   movq	%rdx, %rsi
   movq	%rax, %rdi
   call	_ZNSolsEPFRSoS_E@PLT
   movl	$0, %eax
   movq	-8(%rbp), %rdx
   subq	%fs:40, %rdx
   je	.L7
   call	__stack_chk_fail@PLT
.L7:
   leave
   .cfi_def_cfa 7, 8
   ret
   .cfi_endproc
.LFE1733:
   .size	main, .-main
   .type	_Z41__static_initialization_and_destruction_0ii, @function
_Z41__static_initialization_and_destruction_0ii:
.LFB2237:
   .cfi_startproc
   endbr64
   pushq	%rbp
   .cfi_def_cfa_offset 16
   .cfi_offset 6, -16
   movq	%rsp, %rbp
   .cfi_def_cfa_register 6
   subq	$16, %rsp
   movl	%edi, -4(%rbp)
   movl	%esi, -8(%rbp)
   cmpl	$1, -4(%rbp)
   jne	.L10
   cmpl	$65535, -8(%rbp)
   jne	.L10
   leaq	_ZStL8__ioinit(%rip), %rax
   movq	%rax, %rdi
   call	_ZNSt8ios_base4InitC1Ev@PLT
   leaq	__dso_handle(%rip), %rax
   movq	%rax, %rdx
   leaq	_ZStL8__ioinit(%rip), %rax
   movq	%rax, %rsi
   movq	_ZNSt8ios_base4InitD1Ev@GOTPCREL(%rip), %rax
   movq	%rax, %rdi
   call	__cxa_atexit@PLT
.L10:
   nop
   leave
   .cfi_def_cfa 7, 8
   ret
   .cfi_endproc
.LFE2237:
   .size	_Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii
   .type	_GLOBAL__sub_I_main, @function
_GLOBAL__sub_I_main:
.LFB2238:
   .cfi_startproc
   endbr64
   pushq	%rbp
   .cfi_def_cfa_offset 16
   .cfi_offset 6, -16
   movq	%rsp, %rbp
   .cfi_def_cfa_register 6
   movl	$65535, %esi
   movl	$1, %edi
   call	_Z41__static_initialization_and_destruction_0ii
   popq	%rbp
   .cfi_def_cfa 7, 8
   ret
   .cfi_endproc
.LFE2238:
   .size	_GLOBAL__sub_I_main, .-_GLOBAL__sub_I_main
   .section	.init_array,"aw"
   .align 8
   .quad	_GLOBAL__sub_I_main
   .section	.rodata
   .align 8
.LC0:
   .long	-1717986918
   .long	1074633113
   .align 8
.LC1:
   .long	0
   .long	1074003968
   .hidden	__dso_handle
   .ident	"GCC: (Ubuntu 11.3.0-1ubuntu1~22.04.1) 11.3.0"
   .section	.note.GNU-stack,"",@progbits
   .section	.note.gnu.property,"a"
   .align 8
   .long	1f - 0f
   .long	4f - 1f
   .long	5
0:
   .string	"GNU"
1:
   .align 8
   .long	0xc0000002
   .long	3f - 2f
2:
   .long	0x3
3:
   .align 8
4:

在这个汇编代码中,可以看到两个 add 函数的名称发生了变化,它们被命名为 _ZN4Math3addEii 和 _ZN4Math3addEdd。这些名称修饰是由编译器根据函数的参数类型生成的,以确保在汇编级别可以区分这两个重载函数。

这个示例演示了名称修饰在涉及到函数重载的情况下的应用,以确保正确的函数被调用。在实际应用中,名称修饰对于支持函数重载、运算符重载以及类的成员函数等高级语言特性非常重要。文章来源地址https://www.toymoban.com/news/detail-690141.html

到了这里,关于【c/c++】c和cpp混合编译的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • GO编程语言:简洁、高效、强大的开源编程语言

    在现代软件开发领域,随着应用复杂度的不断提升,开发人员对编程语言的需求也日益增长。GO编程语言,作为一种简洁、高效且具备强大并发能力的新型开源编程语言,逐渐成为了许多开发者的首选。本文将详细介绍GO语言在哪些项目开发中表现出色,以及为什么许多开发者

    2024年02月02日
    浏览(107)
  • 介绍一些编程语言—C语言

    C 语言是一门 面向过程 的计算机编程语言,与 C++、C#、Java 等面向对象编程语言有所不同。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、仅产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。 C语言描述问题比汇编语言迅速、工作量小

    2024年02月13日
    浏览(54)
  • 介绍一些编程语言— Perl 语言

    Perl 是一种动态解释型的脚本语言。 最初的设计者为拉里・沃尔,它于 1987 1987 1987 年 12 12 12 月 18 18 18 日发表。Perl 借取了 C、sed、awk、shell scripting 以及很多其他编程语言的特性。其中最重要的特性是他内部集成了正则表达式的功能,以及巨大的第三方代码库 CPAN。 1987 1987

    2024年02月12日
    浏览(57)
  • 【编程语言 · C语言 · 函数指针】

    由于指针可以指向任何存储器位置中的地址,因此它们也可以指向可执行代码的开头。 函数指针或函数指针指向内存中函数的可执行代码。函数指针可以存储在数组中,也可以作为参数传递给其他函数。 函数指针声明使用 * 就像使用任何指针一样: (*func_name)  周围的括号很

    2024年02月10日
    浏览(57)
  • Go语言网络编程(socket编程)http编程

    Web服务器的工作原理可以简单地归纳为 客户机通过TCP/IP协议建立到服务器的TCP连接 客户端向服务器发送HTTP协议请求包,请求服务器里的资源文档 服务器向客户机发送HTTP协议应答包,如果请求的资源包含有动态语言的内容,那么服务器会调用动态语言的解释引擎负责处理“

    2024年02月09日
    浏览(70)
  • Go语言网络编程(socket编程)WebSocket编程

    WebSocket是一种在单个TCP连接上进行全双工通信的协议 WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据 在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输 需要安装第

    2024年02月09日
    浏览(78)
  • 【编程】C++语言编程规范-2

    结合C++ Effective系列参考树、尤其是工程经验教训的总结。 并发 除非必要,尽量少用线程。 多线程编程要守护好内存,使用atomic、mutex、condition variable、future、semaphore、latch、barrier等同步机制避免数据竞争。 尽量缩小临界区,临界区指独占的资源,禁止其他线程访问变量的代

    2024年02月21日
    浏览(52)
  • 【编程语言 · C语言 · while语句】

    循环 在前面我们了解到, 程序在运行时可以通过判断, 检验条件作出选择。此处,程序还必须能够重复, 也就是反复执行一段指令, 直到满足某个条件为止。 while 语句 while语句可以执行循环结构。 语法: 其一般形式如下: while 语句首先检验一个条件,也就是括号中的表达

    2024年02月08日
    浏览(50)
  • 【编程语言 · C语言 · 字符串】

    C中的字符串是一个以NULL字符\\\'\\0\\\'结尾的字符数组。 字符串声明可以通过多种方式进行,每种方式都有其各自的考虑因素。 例如: 这将创建一个由str_len个字符组成的名为str_name的字符串,并将其初始化为值“ string”。 提供字符串文字以初始化字符串时,编译器会自动将NULL字符

    2024年02月09日
    浏览(45)
  • 【编程语言 · C语言 · for语句】

    C语言中,使用for语句也可以控制一个循环,并且在每一次循环时修改循环变量。在循环语句中,for语句的应用最为灵活,不仅可以用循环次数已经确定的情况,而且可以用于循环次数不确定而只给出循环结束条件的情况。 for 语法: 执行for语句时,程序首先计算第一个表达式

    2024年02月08日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包