C语言的编译

1.C语言的主要标准版本

  • 1972诞生,Dennis Ritchie 设计。
  • ANSI C89,于1989年由ANSI发布
  • C90和ANSI C89是一个标准,只不过C90是由ISO组织发布,后续的版本也是由ISO采纳发布。
  • C99 新特性:
    • 支持单行注释//
    • 允许变长数组
      #include <stdio.h>
      #include <stdlib.h>
      
      int main(int argc, char *argv[])
      {
          int n = atoi(argv[1]);
          // int a[n] = {};//不能初始化,否则编译报错error: variable-sized object may not be initialized
          int a[n];
          printf("%d %ld\n", n, sizeof(a));
      
          return 0;
      }
      
    • 支引入布尔类型
    • 支持内联函数
    • 允许在表达式中直接创建匿名的结构体或数组
       print((struct position){0, 1});
       print((int[]){1, 2});
      
  • C11 新特性:
    • 引入多线程和原子操作
    • 引入_Generic关键字,支持泛型编程。
    • 引入_Noreturn关键字,声明一个函数不会返回。
    • 允许在结构体和联合体中定义匿名成员
    • 引入了<stdbounds.h>头文件,用于边界检查
  • C17 主要是对C11的小幅度更新和修正,没有引入重大新特性。
  • C23 标准进一步现代化了C语言,引入了许多新特性。
    • 允许在字符串字面量之间使用空格进行连接,而不需要使用反斜杠
       #include <stdio.h>
      
       int main() {
         const char *message = "Hello, " "C23!";
         printf("%s\n", message);
         return 0;
       }
      
    • 引入了内置的动态数组类型,使用[]语法可以更方便地创建和管理动态数组
      #include <stdio.h>
      #include <stdlib.h>
      
      int main(int argc, char **argv)
      {
          int n = 5;
          int arr[] = new int[n];  // 创建动态数组
          for (int i = 0; i < n; i++) {
              arr[i] = i;
          }
          for (int i = 0; i < n; i++) {
              printf("%d ", arr[i]);
          }
          printf("\n");
          delete[] arr;  // 释放动态数组
          return 0;
       }
      
    • 引入了[[attributes]]语法,用于指定函数或变量的属性。
    • 增强了_Generic关键字的支持。
    • 引入了许多新的库函数,如strdup、strndup等。

2.gcc 编译指定版本

gcc *.c -std=<version>
gcc -Wall foo.c -o foo -std=C89

使用gcc作为编译器时,由于GNU C对标准进行了一些扩展,导致在指定版本编译时支持了标准版本不支持的特性。
可以使用-pedantic告诉编译器,仅使用指定的标准,不进行扩展,如果涉及到扩展进行警告。
使用-pedantic-errors,仅使用指定的标准,不进行扩展,如果涉及到扩展报错。

test.c

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

void print(int *a)
{
    printf("%d\n", a[0]);
}

int main(int argc, char *argv[])
{
    print((int[]){1, 2});
    return 0;
}

代码使用了c99的特性

dhl@dhl:~$ gcc test.c -std=c89
dhl@dhl:~$ 

正常时不应该编译成功的,实际编译成功,因为gcc 扩展了GUN C

dhl@dhl:~$ gcc test.c -pedantic -std=c89
test.c: In function ‘main’:
test.c:12:18: warning: ISO C90 forbids compound literals [-Wpedantic]
   12 |     print((int[]){1, 2});
      |                  ^

使用-pedantic,不适用GNU扩展,产生警告,但会编译通过,能够运行

dhl@dhl:~$ gcc test.c -pedantic-errors -std=c89
test.c: In function ‘main’:
test.c:12:18: error: ISO C90 forbids compound literals [-Wpedantic]
   12 |     print((int[]){1, 2});
      |                  ^

使用-pedantic-errors,不适用GNU扩展,产生编译错误

3.查看本地gcc默认支持版本

在man gcc中搜索 default for C code
image

4.开源软件编译

4.1 本地编译

一般开源软件会有README文档,指导编译,通常的流程如下:

./configure --prefix=<installPath>
make
make install

installPath是想要安装应用的绝对路径,一般会在路径下生成bin lib等目录,包含生成的可执行文件、依赖库等。
也可能会遇到没有configure的情况,这是需要使用autoreconf工具,这个工具可以根据configure.ac 文件和 Makefile.am 模板,生成 configure 脚本。
如果系统没有命令则安装工具和依赖,Ubuntu系统下可以使用命令sudo apt-get install automake autoconf libtool
在使用autoreconf -ivf生成configure

4.2交叉编译

交叉编译可能会碰到各种问题,比如需要先行交叉编译依赖库,在编译时指定依赖库等等,后面补充具体实例

posted @ 2025-08-11 16:36  宏浪  阅读(12)  评论(0)    收藏  举报