首页
关于
Search
1
云服务器使用
7 阅读
2
C语言基础知识
6 阅读
3
获取歌曲资源
2 阅读
4
一、QEMU简介
2 阅读
5
二、QEMU快速入门
2 阅读
默认分类
私密
统计
食
打扮自己?
游戏
qemu
嵌入式
生活常识
股票
人工智能AI
C/C++
编程语言
C
C++
JavaScript
C#
TypeScript
Java
Python
登录
Search
Typecho
累计撰写
18
篇文章
累计收到
0
条评论
首页
栏目
默认分类
私密
统计
食
打扮自己?
游戏
qemu
嵌入式
生活常识
股票
人工智能AI
C/C++
编程语言
C
C++
JavaScript
C#
TypeScript
Java
Python
页面
关于
搜索到
4
篇与
编程语言
的结果
2025-03-02
GCC
gcc介绍GCC生成动态链接库如果想创建一个动态链接库,可以使用GCC的-shared选项,输入文件可以是源文件汇编文件或者目标文件;另外还需要结合-fPIC文件,-fPIC选项作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),产生的代码中就没有绝对路径了,全部使用相对路径,可以被加载器加载到内存的任意位置且正确地执行例如,从源文件生成动态链接库:gcc -fPIC -shared fun.c -o libfun.so从目标文件生成动态链接库:gcc -fPIC -c fun.c -o func.o gcc -shared fun.o -o libfun.so-fPIC选项作用于编译阶段,在生成目标文件时就得使用该选项,以生成位置无关代码
2025年03月02日
0 阅读
0 评论
0 点赞
2025-03-02
头文件和库文件的搜索路径
一个程序能正确编译、链接、运行需要满足3个条件:预处理时能找到头文件,连接时能找到库(静态库或动态库),运行时能找到库1、头文件的搜索路径头文件通常以.h结尾,有两种写法:双引号和尖括号(当然也可以直接写绝对路径,那就不会有查找路径的问题了),如下:#include <iostream> #include "demo.h"它们查找路径的顺序是有区别的,双引号形式会查找当前路径,而尖括号形式不会,具体查找顺序为:当前目录(仅双引号形式)编译时指定的路径(使用 CMake 编译时,target_include_directories 配置的搜索路径 > include_directories 配置的搜索路径;使用gcc编译时,gcc -I 指定的搜索路径)系统环境变量CPLUS_INCLUDE_PATH( C++ 中) 或 C_INCLUDE_PATH ( C 中)指定的目录gcc默认目录:gcc的默认目录可通过echo | g++ -v -x c++ -E -查看~: echo | g++ -v -x c++ -E - ... #include "..." search starts here: #include <...> search starts here: /usr/include/c++/11 /usr/include/x86_64-linux-gnu/c++/11 /usr/include/c++/11/backward /usr/lib/gcc/x86_64-linux-gnu/11/include /usr/local/include /usr/include/x86_64-linux-gnu /usr/include ...例如:这里会从 /usr/include/c++/11目录依次找到 /usr/include目录库文件的搜索路径
2025年03月02日
1 阅读
0 评论
0 点赞
2025-03-02
extern "C"
在.h文件中(函数的实现在对应的.c文件中),经常会看到这样的代码:#ifdef __cplusplus extern "C" { #endif ... 函数声明 ... #ifdef __cplusplus } #endif这样做的原因是什么呢?首先我们要弄清楚C++和C编译的区别,以 fun 函数为例:// fun.h中声明 int fun(int a, int b); // fun.c中实现 # include "fun.h" int fun(int a, int b){ return a + b; }fun函数在 C 的编译中会被编译成 _fun,在 C++ 中会被编译成 _fun_int_int;(C 对函数的编译在转换成汇编代码的时候只取函数名,而 C++ 是函数名加上参数类型;因此 C++ 支持函数的重载,而 C 不支持函数的重载);如果 cpp 文件调用了 .h(在.c文件中实现) 文件中的 fun 函数,编译链接时会按照_fun_int_int 来找,就会找不到fun函数;如果加上extern "C",C++就会按照_fun来找fun函数,就可以找到该函数;因此解决方法有以下两种(刚好对应extern "c"的使用场景):1、在cpp文件中使用extern "c"声明使用到的c函数// cpp文件中 extern "C"{ // 用extern "C"声明fun.cpp文件中的函数,以至于可以在cpp文件中使用 extern int fun(int a, int b); }2、在.h文件中加上extern "c"(推荐)extern "C"只是C++的关键字,不是 c 的,c 不认识extern "c",所以需要加上ifdef __cplusplus,这样c和cpp文件都可以顺利调用#ifdef __cplusplus extern "C" #endif ... // 函数声明 ... #ifdef __cplusplus } #endif
2025年03月02日
2 阅读
0 评论
0 点赞
2025-02-05
C语言基础知识
defineextern "C"(已完成):在C++中,如果需要使用c语言中的库文件,可以使用extern "C"去包含一、基础知识1、头文件头文件(通常以.h结尾)主要用于声明函数、宏、结构体、联合体、枚举类型等,它们的主要作用是提供接口,使得多个源文件(通常以.c结尾)可以共享这些声明。头文件不应该包含函数或全局变量的定义,这样会导致多重定义问题,即多个源文件可能包含相同的定义,导致链接时错误1、extern 和extern "c"extern常常放在函数的前面成为函数声明的一部分,那么,C语言的关键字extern在函数的声明中起到什么作用?函数默认是extern的,下述两个函数声明没有明显的区别;显式使用extern关键字可以增强代码的可读性,表明这个函数是在另一个文件中定义的;extern int f(); int f();当然,这样的用处还是有的,就是在程序中取代include "*.h"来声明函数;在一些复杂的项目中,我比较习惯在所有的函数声明前添加extern修饰,关于这样做的原因和利弊可见下面这个例子:(1)在test1.h中有下列声明:#ifndef TEST1H #define TEST1H extern char g_str[]; // 声明全局变量g_str void fun1(); #endif(2)在test1.cpp中:#include "test1.h" char g_str[] = "123456"; // 定义全局变量g_str void fun1(){ cout << g_str << endl; }(3) 以上是test1模块,它的编译和链接都可以通过,如果我们还有test2模块也想使用g_str,只需要在原文件中引用就可以了;test2.cpp如下:#include "test1.h" void fun2(){ cout << g_str << endl; }以上test1和test2可以同时编译链接通过,如果你感兴趣的话可以用ultraEdit打开test1.obj,可以在里面找到"123456"这个字符串,但是却不能在test2.obj里面找到,这是因为g_str是整个工程的全局变量,在内存中只存一份,test2.obj这个编译单元不需要再有一份了,不然在链接时报告重复定义的错误(4)有些人喜欢把全局变量的声明和定义放在一起,这样可以防止忘记定义,如把上面的test1.h改为:extern char g_str[] = "123456"; // 这个时候相当于没有extern然后把test1.cpp中g_str的定义去掉,这个时候再编译test1和test2这两个模块时,会报链接错误,这是因为把全局变量的定义放在了头文件之后,test1.cpp这个模块包含了test1.h,而test2.cpp也包含了test1.h,所以再一次定义了g_str,这个时候链接器在链接test1和test2时发现两个g_str如果你非要把g_str的定义放在test1.h中,那么就需要把test2.cpp中的#include "test1.h"去掉换成:extern char g_str[]; void fun2(){ cout << g_str << endl; } 这个时候编译器就知道g_str是一个引自外部的一个编译模块了,不会在模块中重复定义一个;但是这样做非常糟糕,因为你无法在test2.cpp中使用#include "test1.h"了,那么test1.h中声明的其他函数你也无法使用了,除非也都用extern修饰,这样的话光声明的函数就要一大串,而且头文件的作用就是要给外部提供接口使用的。所以请记住,只在头文件中做声明,不应包含函数和全局变量的定义extern 和const、extern和static:https://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777431.html4、头文件和库文件的搜索路径头文件头文件通常以.h结尾一般有两种形式的写法:双引号和尖括号(当然也可以直接写绝对路径,那就不会有查找路径的问题了),如下:#include <iostream> #include "demo.h"它们查找路径的顺序是有区别的,双引号形式会查找当前路径,而尖括号形式不会,具体查找顺序为:1、当前目录(仅双引号形式)2、编译时指定的路径(CMake中target_include_directories配置的搜索路径、CMake中include_directories配置的搜索路径、gcc -I指定的搜索路径)3、系统环境变量CPLUS_INCLUDE_PATH(C++头文件)或C_INCLUDE_PATH(C头文件)指定的目录4、gcc默认目录:/usr/include; /usr/local/include; /usr/lib/gcc/x86_64-linux-gnu/5/5include (注:最后一个路径是gcc程序的库文件路径,各个用户的系统上可能不一样)如果各个目录下存在相同的文件,则先找到哪个就使用哪个,这时顺序很重要gcc的默认目录与安装gcc时指定的--prefix有关,该值可通过gcc -v查看,具体的目录可通过echo | g++ -v -x c__ -E -查看,如下:~: echo | g++ -v -x c++ -E - ... #include "..." search starts here: #include <...> search starts here: /usr/local/include /opt/buildtools/gcc-7.3.0/include /opt/buildtools/gcc-7.3.0/gcc/x86_64-pc-linux-gnu/7.3.0/include-fixed /usr/include ...添加路径到头文件的搜索路径:一般使用CMakeLists.txt或Makefile库文件库文件可以分为静态库(.a文件)和动态库(.so文件)两种链接时库文件的搜索路径为:1、编译时指定的库文件目录(由gcc -L参数指定)2、环境变量LIBRARY_PATH指定的目录3、系统默认目录:/lib; /usr/lib; /usr/local/lib;一般用户安装的库会安装在/usr/local/lib,系统自带的库位于/lib 和 /usr/lib,用户自己编译的库要使用-L参数指定一、数组在C语言中,定义数组只能使用常量可变长数组?二、字符串函数fgets:从文件/终端读取字符串函数原型:char fgets(char str, int n, FILE *fp);函数参数:str为字符数组,n为要读取的字符数目,fp为文件指针函数返回值:读取成功返回字符串数组首地址,即str;读取失败返回NULL注意:读取到的字符串会在末尾自动添加'\0',n个字符也包括'\0';也就是说,实际只读到n-1个字符在读取到n-1个字符之前如果出现了换行,或者读取到了文件末尾,则读取结束;这意味着,不管n的值多大,fgets最多只能读取一行数据,不能跨行fgets遇到换行时,会将换行符一并读取到字符数组中fgets也可以从标准输入(即终端)读取一行字符,将第三个参数改为stdin即可fgets使用如下:// 逐行读取文件 #include <stdio.h> #include <stdlib.h> #define N 100 int main(){ FILE *fp = fopen("demo.txt", "rt"); char str[N+1]; IF(fp == NULL){ printf("Cannot open file\n"); exit(0); } while(fgets(str,N,fp) != NULL){ printf("%s", str); } fclose(fp); return 0; }假设demo.txt如下:123456789终端输出结果和demo.txt一致,每次读取到的字符串中的str[3]即为换行(ASCII码 10),str[4]为'\0'(ASCII码 0)fputs:将字符串写入文件的函数函数原型:int fputs(char str, FILE fp);函数参数:str为要写入的字符串,fp为指向待写入文件的指针返回值:若成功则返回写入的字符个数,失败返回EOF注意:fputs也可以将字符串写入标准输出(即终端),只需将第二个参数改为stdoutfputs不会自动在字符串末尾添加一个换行符,它只会写入直到遇到'\0'如果遇到换行符,会将换行符写入strlen:获取字符串的长度函数原型:int strlen(char const *string);返回值:返回字符串中字符的个数,不会包括'\0'结束符strcpy/strncpy:字符串拷贝函数函数原型:char strcpy(char dest, char *src); char strncp(char dest, char *src, int size);dest指向目标字符串,src指向源字符串;函数的作用为将源字符串拷贝到目标字符串参数:dest:指向用于存储复制内容的目标数组;src:要复制的字符串返回值:返回指向目标字符串的指针注意:将src
2025年02月05日
6 阅读
0 评论
0 点赞