记录一些 C 语言零散知识点。
未分类
Visual Studio 中防止编译器报错
#define _CRT_SECURE_NO_WARNINGS
防止程序一闪而过:
#include "windows.h"
int main(void)
{
system("pause");
return 0;
}
常用预定义宏:
__FILE__:是当前编译的文件的文件名 是一个字符串
__TIME__:是当前编译的文件的编译时间 格式是hh:mm:ss 是字符串
__DATE__:是当前编译的文件的编译日期 格式是Mmm:dd:yyyy 是字符串
__LINE__:是调用该宏语句所在的行数,是个十进制数
两点直线拟合:
static double LineFit(double x)
{
const double x0 = 0.1;
const double x1 = 0.2;
const double y0 = 100.0;
const double y1 = 150.0;
double rate, result;
rate = (y1 - y0) / (x1 - x0);
result = y0 + rate * (x - x0);
return result;
}
下述代码实现了结构体按 1 字节对齐。
//方式一
#pragma pack(1)
typedef struct
{
int a,
char b,
double c,
}Struct;
#pragma pack()
//方式2
#pragma pack(push)
#pragma pack(1)
typedef struct
{
int a,
char b,
double c,
}Struct;
#pragma pack(pop)
下述代码实现了数组起始地址按照 32 字节对齐。
__align(32) unsigned char s_arrDataBuf[1024] = {0};
下述代码实现了将数组起始地址固定分配到 0x6C000000。
__align(32) unsigned chars_arrDataBuf[1024] __attribute__((at((u32)0x6C000000)));
字符串相关
追加字符串:
/*********************************************************************************************************
* 函数名称:StringAdd
* 函数功能:追加字符串
* 输入参数:target:目标字符串,add:追加的字符串
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:
*********************************************************************************************************/
void StringAdd(char* target, char* add)
{
unsigned int i, j;
//确定目标字符串结尾
i = 0;
while(0 != target[i]) {i++;}
//拷贝字符串
j = 0;
while(0 != add[j])
{
target[i] = add[j];
i++;
j++;
}
//加上字符串结尾
target[i] = 0;
}
修改文件名后缀:
/*********************************************************************************************************
* 函数名称:NameModifySuffix
* 函数功能:修改文件名后缀
* 输入参数:name:当前文件名(含后缀),suffix:目标后缀
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年08月31日
* 注 意:
*********************************************************************************************************/
void NameModifySuffix(char* name, char* suffix)
{
unsigned int pointPos; //后缀点所在位置
unsigned int i; //循环变量
pointPos = 0;
i = 0;
while (0 != name[i]) //查找后缀起始位置
{
if ('.' == name[i])
{
pointPos = i;
}
i++;
}
name[pointPos + 1] = 0;
StringAdd(name, suffix);
}
从字符串中移除某个字符:
/*********************************************************************************************************
* 函数名称: StringRemoveChar
* 函数功能: 从字符串中移除某个字符
* 输入参数: string:需要操作的字符串,c:需要移除的字符
* 输出参数: void
* 返 回 值: void
* 创建日期: 2023年08月31日
* 注 意:
*********************************************************************************************************/
static void StringRemoveChar(char* string, char c)
{
char* str;
while (0 != *string)
{
if (*string == c)
{
str = string;
while (0 != *str)
{
*str = *(str + 1);
str++;
}
}
string++;
}
}
替换字符串中的字符
/*********************************************************************************************************
* 函数名称: StringReplaceChar
* 函数功能: 替换字符串中的字符
* 输入参数: string:需要操作的字符串,cold:旧字符,cnew:新字符
* 输出参数: void
* 返 回 值: void
* 创建日期: 2023年08月31日
* 注 意:
*********************************************************************************************************/
static void StringReplaceChar(char* string, char cold, char cnew)
{
while (0 != *string)
{
if (*string == cold)
{
*string = cnew;
}
string++;
}
}
字符串查找:
/*********************************************************************************************************
* 函数名称: FindString
* 函数功能: 查找字符串
* 输入参数: source:源字符串首地址,即可能含有目的字符串的字符串首地址
* target:目的字符串首地址
* 输出参数: void
* 返 回 值: 目的字符串距离源字符串首地址偏移量,0xFFFFFFFF 表示查找失败
* 创建日期: 2023年09月04日
* 注 意:
*********************************************************************************************************/
#define STRING_NODE_INVALID 0xFFFFFFFF
static unsigned int FindString(char* source, char* target)
{
unsigned int i, j, k, ok;
i = 0; j = 0; k = 0; ok = 0;
while(0 != source[i])
{
//检测到目的字符串的开头
if(source[i] == target[0])
{
j = i;
k = 0;
while((0 != source[j]) && (0 != target[k]))
{
if(source[j] == target[k])
{
j++; k++;
}
else
{
break;
}
}
//成功查找到目的字符串
if(0 == target[k])
{
ok = 1;
break;
}
}
i++;
}
//成功查找带字符串
if(ok)
{
return i;
}
else
{
return STRING_NODE_INVALID;
}
}
打印函数封装:
#include "stdio.h"
#include "stdarg.h"
/*********************************************************************************************************
* 函数名称: PrintString
* 函数功能: 字符串打印函数
* 输入参数: fmt:字符串数据
* 输出参数: void
* 返 回 值: void
* 创建日期: 2023年08月19日
* 注 意:
*********************************************************************************************************/
static void PrintString(char* fmt, ...)
{
//字符串转换缓冲区
static char s_arrStringBuf[1024];
//字符串长度
unsigned int len;
//定义一个 va_list 类型的变量,用来存储单个参数
va_list args;
//为空,直接返回
if(NULL == fmt)
{
return;
}
//使 args 执行可变参数的第一个参数
va_start(args, fmt);
//字符串转换
vsprintf(s_arrStringBuf, fmt, args);
//统计字符串长度
len = 0;
while(0 != s_arrStringBuf[len]){ len++; }
//输出到串口
WriteUART0((void*)s_arrStringBuf, len);
//结束可变参数的获取
va_end(args);
}
获取字符串输入:
char string[100];
printf("input a file name:");
scanf("%s", string);
字符串、数字转换
10 进制字符串转整型,代码如下。
/*********************************************************************************************************
* 函数名称: StringToInt
* 函数功能: 10 进制字符串转整型
* 输入参数: string:字符串形式的数字
* 输出参数: void
* 返 回 值: 转换结果
* 创建日期: 2023年02月10日
* 注 意: 不能含有数字、正负号等其它符号
*********************************************************************************************************/
static int StringToInt(char* string)
{
int sum;
int negative;
unsigned int i;
sum = 0;
i = 0;
negative = 0;
while(('+' == string[i]) || ('-' == string[i]) || ((string[i] >= '0') && (string[i] <= '9')))
{
//正号
if ('+' == string[i])
{
negative = 0;
}
//负号
else if ('-' == string[i])
{
negative = 1;
}
//空格
else if (' ' == string[i])
{
//不做处理
}
//数字
else if ((string[i] >= '0') && (string[i] <= '9'))
{
sum = (sum * 10) + (string[i] - '0');
}
//循环变量加一
i++;
}
//负号处理
if (0 != negative)
{
sum = -sum;
}
//返回转换结果
return sum;
}
字符串转浮点数,代码如下。
/*********************************************************************************************************
* 函数名称: StringToDouble
* 函数功能: 字符串转浮点数
* 输入参数: void
* 输出参数: void
* 返 回 值: void
* 创建日期: 2023年07月13日
* 注 意: 除数字、正负号、小数点外,不得带有其它符号
*********************************************************************************************************/
static double StringToDouble(char* string)
{
double sum, devision;
int negative, dotFlag;
unsigned int i;
sum = 0;
negative = 0;
i = 0;
devision = 1;
dotFlag = 0;
while(('+' == string[i]) || ('-' == string[i]) || ('.' == string[i]) || ((string[i] >= '0') && (string[i] <= '9')))
{
//正号
if ('+' == string[i])
{
negative = 0;
}
//负号
else if ('-' == string[i])
{
negative = 1;
}
//小数点
else if ('.' == string[i])
{
dotFlag = 1;
}
//空格,不处理
else if (' ' == string[i])
{
}
//数字
else if ((string[i] >= '0') && (string[i] <= '9'))
{
sum = (sum * 10.0) + (string[i] - '0');
if (0 != dotFlag)
{
devision = devision * 10;
}
}
//循环变量加一
i++;
}
//负号处理
if (0 != negative)
{
sum = -sum;
}
//小数点处理
sum = sum / devision;
//返回转换结果
return sum;
}
数值转字符串如下所示。
/*********************************************************************************************************
* 模块名称:SerialString.c
* 摘 要:字符串处理模块
* 当前版本:1.0.0
* 作 者:Leyutek(COPYRIGHT 2018 - 2021 Leyutek. All rights reserved.)
* 完成日期:2021年07月01日
* 内 容:
* 注 意:Bootloarder专用,不要使用printf或sprintf等C语言官方库函数,
* 否则编译器会将C语言官方库编入Bootloarder中,使得Bootloarder程序占用空间大
**********************************************************************************************************
* 取代版本:
* 作 者:
* 完成日期:
* 修改内容:
* 修改文件:
*********************************************************************************************************/
/*********************************************************************************************************
* 包含头文件
*********************************************************************************************************/
#include "SerialString.h"
#include "UART0.h"
/*********************************************************************************************************
* 宏定义
*********************************************************************************************************/
#define MAX_STRING_CONVER_LEN 64 //字符串转换最大长度
/*********************************************************************************************************
* 枚举结构体定义
*********************************************************************************************************/
/*********************************************************************************************************
* 内部变量
*********************************************************************************************************/
//数值-ASCII码转换表
static const char s_arrNumTable[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
//字符串转换缓冲区
static char s_arrStringBuf[MAX_STRING_CONVER_LEN];
/*********************************************************************************************************
* 内部函数声明
*********************************************************************************************************/
/*********************************************************************************************************
* 内部函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* API函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:PutString
* 函数功能:串口输出一个字符串
* 输入参数:string:字符串
* 输出参数:void
* 返 回 值:void
* 创建日期:2021年07月01日
* 注 意:
*********************************************************************************************************/
void PutString(char* string)
{
u32 len; //字符串长度
//统计字符串长度
len = 0;
while(0 != string[len])
{
len++;
}
WriteUART0((unsigned char*)string, len);
}
/*********************************************************************************************************
* 函数名称:PutUint
* 函数功能:串口输出一个10进制无符号整型
* 输入参数:num:显示数值,width:显示宽度,不足补零
* 输出参数:void
* 返 回 值:void
* 创建日期:2021年07月01日
* 注 意:
*********************************************************************************************************/
void PutDecUint(u32 num, u32 width)
{
u32 divisor; //除数1、10、100、1000...
u32 widthDivisor; //显示完整宽度需要的除数大小
u32 needDivisor; //显示完整数字需要的除数大小
u32 stringCnt; //字符串计数
u32 digital; //单个位数据
//计算显示位宽下需要的除数大小
widthDivisor = 1;
while(width)
{
width--;
widthDivisor = widthDivisor * 10;
}
widthDivisor = widthDivisor / 10;
//计算显示完整数字需要的除数大小
needDivisor = 1;
while(num >= needDivisor)
{
needDivisor = needDivisor * 10;
}
needDivisor = needDivisor / 10;
//确定除数初值
if(widthDivisor > needDivisor)
{
divisor = widthDivisor;
}
else
{
divisor = needDivisor;
}
//字符串转换
stringCnt = 0;
while(1)
{
//已经到个位了
if(1 == divisor)
{
digital = num;
s_arrStringBuf[stringCnt++] = s_arrNumTable[digital];
break;
}
else
{
digital = num / divisor; //取出高位
num = num % divisor; //将高位剔除
divisor = divisor / 10; //更新除数
s_arrStringBuf[stringCnt++] = s_arrNumTable[digital]; //数值转ASCII码
}
}
s_arrStringBuf[stringCnt] = 0;
//输出
PutString(s_arrStringBuf);
}
/*********************************************************************************************************
* 函数名称:PutDouble
* 函数功能:串口输出一个浮点数
* 输入参数:num:显示数值,pointNum:小数点位数
* 输出参数:void
* 返 回 值:void
* 创建日期:2021年07月01日
* 注 意:
*********************************************************************************************************/
void PutDouble(double num, u32 pointNum)
{
u32 integer, decimal; //整数、小数转换结果
u32 divisor; //除数1、10、100、1000...
//确定除数
divisor = 1;
while(pointNum)
{
pointNum--;
divisor = divisor * 10;
}
//得到整数部分
integer = (u32)num;
//得到小数部分
num = num * divisor;
decimal = ((u32)num) % divisor;
//显示
PutDecUint(integer, 1); //整数部分
PutString("."); //小数点
PutDecUint(decimal, 1); //小数部分
}
读写文件
C 语言创建并写入二进制文件。
#include <stdio.h>
//创建
FILE* bin = fopen("name.bin", "wb");
//写入
fwrite(buf, xxx, xxx, bin);
//保存
fclose(bin);
C 语言创建并写入 csv 表格文件,csv 文件以 “,” 为数据间的分隔符,以 “\n” 为行切换。
#include <stdio.h>
//创建
FILE* file = fopen("name.csv", "w");
//写入
fprintf(file, "%d,", data);
//保存
fclose(file);
获取用户输入的文件名的代码如下所示。
#include <stdio.h>
/*********************************************************************************************************
* 函数名称: GetFileName
* 函数功能: 获取文件名
* 输入参数: name:名字缓冲区
* 输出参数: void
* 返 回 值: void
* 创建日期: 2023年07月13日
* 注 意:
*********************************************************************************************************/
static void GetFileName(char* name)
{
printf("Please input file name: ");
scanf("%s", name);
}
以文本文件形式将整个文件读入到内存中,代码如下所示
#include <stdio.h>
#include <malloc.h>
/*********************************************************************************************************
* 函数名称: ReadSourceFileToMemoryByChar
* 函数功能: 以文本文件形式将整个文件读入到内存中
* 输入参数: path:文件路径
* size:用于输出文件大小
* 输出参数: void
* 返 回 值: 内存首地址
* 创建日期: 2023年02月10日
* 注 意: 分配内存失败、打开文件失败会直接卡死
*********************************************************************************************************/
static char* ReadSourceFileToMemoryByChar(char* path, unsigned int* size)
{
FILE* sourceFile;
char* buf;
//打开文件(以文本的形式)
sourceFile = fopen(path, "r");
if (NULL == sourceFile)
{
printf("ReadSourceFileToMemoryByChar: Fail to open source file: %s\r\n", path);
while (1) {}
}
//统计文件长度
fseek(sourceFile, 0, SEEK_END);
*size = ftell(sourceFile);
//申请动态内存
buf = malloc(*size);
if (NULL == buf)
{
printf("ReadSourceFileToMemoryByChar: Fail to malloc for source file\r\n");
while (1) {}
}
//跳转到文件开头
fseek(sourceFile, 0, SEEK_SET);
//读入整个文件
fread(buf, *size, 1, sourceFile);
//关闭文件
fclose(sourceFile);
//返回内存首地址
return buf;
}
以二进制文件形式将整个文件读入到内存中,代码如下所示。
#include <stdio.h>
#include <malloc.h>
/*********************************************************************************************************
* 函数名称: ReadSourceFileToMemoryByByte
* 函数功能: 以二进制文件形式将整个文件读入到内存中
* 输入参数: path:文件路径
* size:用于输出文件大小
* 输出参数: void
* 返 回 值: 内存首地址
* 创建日期: 2023年02月10日
* 注 意: 分配内存失败、打开文件失败会直接卡死
*********************************************************************************************************/
static char* ReadSourceFileToMemoryByByte(char* path, unsigned int* size)
{
FILE* sourceFile;
char* buf;
//打开文件(以文本的形式)
sourceFile = fopen(path, "rb");
if (NULL == sourceFile)
{
printf("ReadSourceFileToMemoryByByte: Fail to open source file: %s\r\n", path);
while (1) {}
}
//统计文件长度
fseek(sourceFile, 0, SEEK_END);
*size = ftell(sourceFile);
//申请动态内存
buf = malloc(*size);
if (NULL == buf)
{
printf("ReadSourceFileToMemoryByByte: Fail to malloc for source file\r\n");
while (1) {}
}
//跳转到文件开头
fseek(sourceFile, 0, SEEK_SET);
//读入整个文件
fread(buf, *size, 1, sourceFile);
//关闭文件
fclose(sourceFile);
//返回内存首地址
return buf;
}
Windows 下路径不存在则创建路径:
static void CheckDir(char* dir)
{
if(0 != _access(dir, 0))
{
_mkdir(dir);
}
}