Administrator
Administrator
发布于 2024-12-03 / 15 阅读
0
0

C常规函数学习记录

C语言常用关键字、函数与类型详解

本文档将介绍C语言中的几个常用关键字、函数和类型,包括存储类、字符串转换、网络地址处理、信号处理以及多线程管理。具体内容涵盖 static 关键字、atoiinet_addrsignal、信号编号(signum)以及 pthread_t 类型。

1. 存储类关键字

1.1 static 关键字

功能static 关键字在C语言中用于控制变量和函数的作用域、存储持续性以及链接性。根据变量或函数的声明位置不同,static 具有不同的作用。

1.1.1 静态变量(Static Variables)

  • 在函数内部声明的静态变量: 当 static 用于函数内部的变量时,该变量具有静态存储持续性,意味着变量在程序的整个运行期间都存在,并且其值在多次函数调用之间保持不变。

    #include <stdio.h>
    
    void counter() {
        static int count = 0; // 静态变量
        count++;
        printf("Count: %d\n", count);
    }
    
    int main() {
        counter(); // 输出: Count: 1
        counter(); // 输出: Count: 2
        counter(); // 输出: Count: 3
        return 0;
    }
    

    在上述例子中,count 变量在每次调用 counter 函数时不会被重新初始化,而是保留其上一次的值。

  • 在文件作用域声明的静态变量: 当 static 用于文件作用域(即函数外部)时,变量的链接性被限制为内部链接,意味着该变量只能在声明它的文件内访问,不能被其他文件访问。

    // file1.c
    static int sharedVar = 10; // 仅在file1.c中可见
    
    void printVar() {
        printf("sharedVar: %d\n", sharedVar);
    }
    
    // file2.c
    extern int sharedVar; // 错误:sharedVar在file1.c中是静态的,无法在file2.c中访问
    

1.1.2 静态函数(Static Functions)

static 用于函数声明时,该函数的链接性被限制为内部链接,即该函数只能在声明它的文件内调用,不能被其他文件访问。这在模块化编程中非常有用,可以隐藏内部实现细节。

// file1.c
static void helperFunction() {
    // 仅在file1.c中可见
}

void publicFunction() {
    helperFunction(); // 可以调用
}
// file2.c
void publicFunction();

int main() {
    publicFunction();      // 正确,可以调用
    helperFunction();      // 错误:helperFunction在file1.c中是静态的,无法在file2.c中访问
    return 0;
}

1.1.3 总结

static 关键字在C语言中扮演着重要角色,通过控制变量和函数的生命周期、作用域及链接性,帮助程序员实现更好的模块化、数据隐藏和资源管理。理解并正确使用 static 是编写高效、可维护C程序的基础之一。

2. 字符串与整数转换

2.1 atoi 函数

功能atoi(ASCII to Integer)用于将一个表示整数的字符串转换为对应的整数值。

头文件<stdlib.h>

原型

int atoi(const char *str);

用法示例

#include <stdio.h>
#include <stdlib.h>

int main() {
    char str[] = "12345";
    int num = atoi(str);
    printf("转换后的整数值为: %d\n", num); // 输出: 12345
    return 0;
}

注意事项

  • atoi 不进行错误检查,如果字符串不完全是有效的整数表示,结果可能未定义。推荐使用 strtol 进行更安全的转换。

3. 网络地址处理

3.1 inet_addr 函数

功能inet_addr 用于将一个点分十进制格式的 IPv4 地址(如 "192.168.1.1")转换为一个 unsigned long 类型的网络地址(网络字节序)。

头文件<arpa/inet.h>

原型

unsigned long inet_addr(const char *cp);

用法示例

#include <stdio.h>
#include <arpa/inet.h>

int main() {
    const char *ip_str = "192.168.1.1";
    unsigned long ip_addr = inet_addr(ip_str);
    if (ip_addr == INADDR_NONE) {
        printf("IP地址转换失败\n");
    } else {
        printf("转换后的网络地址: %lu\n", ip_addr);
    }
    return 0;
}

注意事项

  • inet_addr 仅支持 IPv4 地址,对于 IPv6 地址需使用 inet_pton
  • 返回值为 INADDR_NONE 表示转换失败。

4. 信号处理

4.1 signal 函数

功能signal 用于设置信号处理程序,允许程序捕获和处理特定的信号(如程序终止、非法操作等)。

头文件<signal.h>

原型

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

用法示例

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>

void handle_sigint(int sig) {
    printf("捕获到信号 %d(SIGINT),程序即将终止。\n", sig);
    exit(0);
}

int main() {
    // 设置信号处理程序
    signal(SIGINT, handle_sigint);
    
    printf("程序运行中,按 Ctrl+C 来触发 SIGINT 信号...\n");
    while(1); // 无限循环等待信号
    return 0;
}

4.2 信号编号(signum

定义signum 指定信号的类型,常见的信号及其说明如下:

  • SIGINT:用户按下 Ctrl+C 时发送,表示程序被中断。
  • SIGTERM:请求程序终止。
  • SIGSEGV:非法内存访问,通常导致段错误。
  • SIGFPE:浮点运算错误(例如除零)。
  • SIGILL:非法指令。
  • SIGABRT:异常终止信号,通常由程序本身发送。
  • SIGKILL:强制终止程序(无法捕获或忽略)。
  • SIGUSR1, SIGUSR2:用户自定义信号。

信号处理示例

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>

void handle_signal(int signum) {
    switch(signum) {
        case SIGINT:
            printf("接收到 SIGINT 信号(中断信号)。\n");
            break;
        case SIGTERM:
            printf("接收到 SIGTERM 信号(终止信号)。\n");
            break;
        case SIGSEGV:
            printf("接收到 SIGSEGV 信号(段错误)。\n");
            break;
        default:
            printf("接收到信号: %d\n", signum);
    }
    exit(0);
}

int main() {
    // 设置信号处理程序
    signal(SIGINT, handle_signal);
    signal(SIGTERM, handle_signal);
    signal(SIGSEGV, handle_signal);
    
    printf("程序运行中,等待信号...\n");
    while(1); // 无限循环等待信号
    return 0;
}

5. 多线程管理

5.1 pthread_t 类型

定义pthread_t 是 POSIX 线程库(pthreads)中的一个数据类型,用于表示线程的标识符。它用于在多线程程序中唯一标识一个线程。

头文件<pthread.h>

基本用法

  • 创建线程

    #include <stdio.h>
    #include <pthread.h>
    
    void* thread_function(void* arg) {
        printf("新线程正在运行...\n");
        return NULL;
    }
    
    int main() {
        pthread_t thread;
        if(pthread_create(&thread, NULL, thread_function, NULL)) {
            fprintf(stderr, "创建线程失败\n");
            return 1;
        }
        pthread_join(thread, NULL); // 等待线程结束
        return 0;
    }
    
  • 线程标识: 每个线程都有一个唯一的 pthread_t 标识符,可以用于后续的线程管理操作,如等待线程结束、取消线程等。

5.2 线程管理

常用函数

  • pthread_create:创建新线程。
  • pthread_join:等待指定线程结束。
  • pthread_cancel:取消指定线程。
  • pthread_exit:终止调用线程。

线程管理示例

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

void* worker(void* arg) {
    int id = *(int*)arg;
    printf("线程 %d 开始工作。\n", id);
    sleep(2); // 模拟工作
    printf("线程 %d 完成工作。\n", id);
    return NULL;
}

int main() {
    pthread_t threads[3];
    int thread_ids[3] = {1, 2, 3};

    // 创建线程
    for(int i = 0; i < 3; i++) {
        if(pthread_create(&threads[i], NULL, worker, &thread_ids[i])) {
            fprintf(stderr, "无法创建线程 %d\n", i+1);
            return 1;
        }
    }

    // 等待所有线程结束
    for(int i = 0; i < 3; i++) {
        pthread_join(threads[i], NULL);
    }

    printf("所有线程已完成。\n");
    return 0;
}

注意事项

  • 使用 pthread_t 进行线程管理时,应确保线程标识符的唯一性和正确性。
  • 线程间共享资源时,需要使用同步机制(如互斥锁)以避免竞态条件。

6. 总结

本文档介绍了C语言中几个重要的关键字、函数和类型,包括:

  • static 关键字:用于控制变量和函数的作用域、存储持续性及链接性,帮助实现模块化和数据隐藏。
  • atoi:用于字符串与整数之间的转换。
  • inet_addr:用于将字符串形式的IPv4地址转换为网络字节序的地址。
  • signalsignum:用于信号处理,允许程序捕获和响应各种系统信号。
  • pthread_t:POSIX线程标识符,用于多线程编程中的线程管理。

理解并正确使用这些关键字、函数和类型,可以显著提高C程序在存储管理、字符串处理、网络编程、信号响应以及多线程管理等方面的能力。


评论