wangdoc / clang-tutorial Goto Github PK
View Code? Open in Web Editor NEWC 语言教程
Home Page: https://wangdoc.com/clang
C 语言教程
Home Page: https://wangdoc.com/clang
”C 语言允许合并多个字符串字面量“
应该为: “C 语言允许合并多个字符串字变量”
内存管理章节:
“指针变量必须有类型,否则编译器无法知道,如何解读内存块保存的二进制数据。“
建议改成” 指针变量必须有类型,否则编译器不知道如何解读内存块保存的二进制数据。“
https://wangdoc.com/clang/file#fclose
fclose()用来关闭已经使用fopen()打开的文件。它的原型定义在stdin.h。
stdio.h错写成stdin.h了
#if...#end
之间还可以加入#else指令,用于指定判断条件不成立时,需要编译的语句。
string~字符串~字符串变量的声明~第二段文字中“如果采用第一种写法”,这里想表达的好像是第二种
https://github.com/wangdoc/clang-tutorial/blame/main/docs/multifile.md#L80
根据上下文来看, 这里的代码是否应为
// File bar.c
#include "bar.h"
int add(int x, int y) {
return x + y;
}
在 22. 多字节字符 中,
5.1第一行“返回一个多字节字符占用的字符数”应为“返回一个多字节字符占用的字节数”
https://github.com/wangdoc/clang-tutorial/blame/main/docs/file.md#L200
"都会写入foo.txt
"
此处是不是 "都会写入output.txt
"
这种注释一定不能忘记写结束符号*/
,否则很导致错误。
原文是不是想说会导致错误
https://github.com/wangdoc/clang-tutorial/blame/main/docs/array.md#L205
int n = a + b;
int a[n];
两行都有 a
. 没有 get 到这个例子的点
struct breed {
char* name;
int kinds;
};
struct fish {
char* name;
int age;
---> struct species breed;
};
实际上应为
struct breed {
char* name;
int kinds;
};
struct fish {
char* name;
int age;
struct breed species;
};
或是
struct species {
char* name;
int kinds;
};
struct fish {
char* name;
int age;
struct species breed;
};
数组声明的时候,数组长度除了使用常量,也可以使用变量。
有点英式写法,建议:声明数组的时候,数组长度既可以是常量,也可以是变量。
任何长度需要运行时才能确定的数组,都是变长数组。
建议:任何需要运行时才能确定长度的数组 ...
上面示例中,三个数组的长度都需要运行代码才能直到,所以它们都是变长数组。
拼写:直到⇒知道,并且建议改成:才能确定
WangDoc网站的文字一般挺长的,有两个建议
1、导航栏能不能随着滚动条走,总是显示在屏幕右侧,便于选择阅读,特别是再次阅读时是选读的。
2、建议加一个返回顶部的按钮小火箭,便于回到页面内导航,复习阅读。
不知是否可行
感谢阮老师的辛苦付出和无私奉献%%%STO
x = 1, 2, 3;
上面示例中,逗号的优先级高于赋值运算符,所以会执行。由于逗号运算符返回最后一个表达式的值,所以变量x等于3。
x = 1, 2, 3;
执行后 x 的结果是 1,逗号的优先级高于赋值运算符
这句话有误,应该是 逗号的优先级低于赋值运算符,且按从左到右的顺序运算
。所以先运行 =
运算符,直接将 1 赋值给 x。
x = 1, 2, 3;
可以看作 (x = 1), 2, 3;
整个表达式的返回值是 3。
我有服务器,有科学上网条件,想自己搭类似的试试。
给联合体中的某一字段赋值并不会使之前赋值的字段失效,也不会禁止用户访问之前的字段,例如
typedef union {
char c;
int i;
} U;
U u = { .c = 'A' }; // u.i == 65
联合体一般在嵌入式中比较常用,用于使用不同的方式访问寄存器
typedef union {
struct {
unsigned char all_bits;
};
struct {
unsigned char bit0 : 1;
unsigned char bit1 : 1;
unsigned char bit2 : 1;
unsigned char bit3 : 1;
unsigned char bit4 : 1;
unsigned char bit5 : 1;
unsigned char bit6 : 1;
unsigned char bit7 : 1;
};
} U;
这样就可以通过 all_bits
访问、修改整个寄存器的值,或者通过位名称访问、修改指定的位了
另外在 PyTorch 的 c10 模块中,还借助 union 实现了 BF16 数据类型
using int_repr_t = uint16_t;
using float_t = c10::BFloat16;
union {
float_t f;
int_repr_t i;
}
LibTorch 中,BF16、FP16 与 FP32 的转换是通过解释成无符号整形然后使用位运算实现的,如果不使用 union 的话就需要大量使用 std::bit_cast
。而如果使用 union,只需对其整数字段取值、赋值即可,在使用浮点字段的时候相当于自动进行了一次 tsd::bit_cast
。
另外项目名中的 clang 容易与 LLVM 的 C 编译器前端 Clang 产生混淆,建议更名为 c-lang-tutorial
教程挺好的,但是clang有歧义,为了更符合教程内容,建议改个名字
int sum_array(int n, int a[n]) {
// ...
}
int a[] = {3, 5, 7, 3};
int sum = sum_array(4, a);
error C2057: 应输入常量表达式
error C2466: 不能分配常量大小为 0 的数组
NMAKE : fatal error U1077: “C:\PROGRA~2\MICROS~2\2017\BUILDT~1\VC\Tools\MSVC\1416~1.270\bin\Hostx86\x86\cl.exe”: 返回代码“0x2”
Stop.
NMAKE : fatal error U1077: “"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Tools\MSVC\14.16.27023\bin\HostX86\x86\nmake.exe"”: 返回代码“0x2”
Stop.
NMAKE : fatal error U1077: “"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Tools\MSVC\14.16.27023\bin\HostX86\x86\nmake.exe"”: 返回代码“0x2”
Stop.
NMAKE : fatal error U1077: “"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Tools\MSVC\14.16.27023\bin\HostX86\x86\nmake.exe"”: 返回代码“0x2”
Stop.
printf("%+d\n", 12); // 输出 +12 printf("%+d\n", 12); // 输出 -12
上面第二行的参数应该是-12
root@william:~/c# gcc -std=C99 hello.c
gcc: error: unrecognized command-line option ‘-std=C99’; did you mean ‘-std=c99’?
root@william:~/c#
root@william:~/c# gcc --version
gcc (Ubuntu 10.3.0-1ubuntu1) 10.3.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
root@william:~/c# gcc -std=c99 hello.c
root@william:~/c#
变量的作用域
链接文章结尾处的代码
for (int i = 0; i < 5; i++) {
int i = 999;
printf("%d\n", i);
}
printf("%d\n", i); // 非法
运行报错 error: redeclaration of 'int i'
老师想表达的是嵌套循环的作用域?
for (int i = 0; i < 5; i++)
{
for (int i = 0; i < 3; i++)
{
//...
}
}
见行:
clang-tutorial/docs/preprocessor.md
Line 231 in 1e70e6f
C 语言标准要求至少定义以下类型。
- int8_t uint8_t
- int16_t uint16_t
- int32_t uint32_t
- int64_t uint64_t
- int_least8_t uint_least8_t
- int_least16_t uint_least16_t
- int_least32_t uint_least32_t
- int_least64_t uint_least64_t
- int_fast8_t uint_fast8_t
- int_fast16_t uint_fast16_t
- int_fast32_t uint_fast32_t
- int_fast64_t uint_fast64_t
据 cppreference,int8_t、int16_t、int32_t、int64_t uint8_t、uint16_t、uint32_t、uint64_t 皆为可选实现。
读了阮老师的ssh系列和C系列,感觉收获很大,但总有种拾人牙慧的感觉,如果能把笔记对应的参考书籍或者文档链接也发一下,就再好不过了,我想对照着看看,这样不仅能巩固一下,也能学学如何做笔记的。
2.void指针 中的第一段代码
int x = 10;
void* p = &x; // 整数指针转为 void 指针
int* q = p; // void 指针转为整数指针
这里的两行注释是不是顺序颠倒了,第一行不应该是无类型指针p转为int类型指针吗?还是我理解有问题?
函数举例
FILE* fopen(char* filename, char* mode, FILE stream);
应改为
FILE* freopen(char* filename, char* mode, FILE stream);
flow-control 9 goto 语句
goto 的一个主要用法是跳出多层循环。
上面代码有很复杂的嵌套循环,不使用 goto 的话,想要完全跳出所有循环,写起来很麻烦。
一般来说可以提取成一个函数,return时就全跳出了。
function 7.1 extern 说明符
对于多文件的项目,源码文件会用到其他文件声明的函数。这时,当前文件里面,需要给出外部函数的原型,并用extern说明该函数的定义来自其他文件。
函数的声明不需要extern,后面specifier这一章里也说了。
string
对于字符串常量,只在最开始写char* s = 'xxx';
,等到引入无法修改的问题后,之后的代码一直用const char *
。
struct
一般不说“struct命令”吧。
一、第10项 fscanf():......而fscanf()是从文件读入数据,它的原因定义在头文件stdio.h......
此处应该是“它的原型定义在头文件stdio.h”
二、第13项fwrite(): fwrite()以及后面要介绍的 fwrite(),比较适合读写二进制数据......
此处应该是指后面的 fread 函数吧
https://github.com/wangdoc/clang-tutorial/blame/main/docs/operator.md#L225
因为表示运算符是从左到右计算,
是不是应该为
因为关系运算符是从左到右计算,
“如果采用第一种写法,由于字符数组的长度可以让编译器自动计算,所以声明时可以省略字符数组的长度。”
应为“第二种写法”
取值范围错误(ERANGE):函数的返回值太大,无法用返回类型白哦是。
这里最后的'白哦是'是不是写错了?
还是故意卖萌呢?😆
可以多介绍一些如何引用第三方库相关的知识吗?比如将ffmpeg,boost 编译成动态链接库,也不知道该看什么资料,所查到的都是雷同的编译脚本。
%a
和 %A
的说明应该改为 "十六进制浮点数的p-记法", 或者网上常见的 "浮点数、十六进制数字和p-记数法".%f
才是 "浮点数".short* j;
j = (short*)0x1234;
j = j + 1; // 0x1236
j = j + 2; // 0x1238
对于加1的结果解释是“向高位移动两个字节”(这句话是不是有点问题?);
两个字节对于二进制来说是16位,意思是向高位即左移动16位吗?
我将0x1234转换成二进制是0001001000110100,0x1236转换成二进制是0001001000110110,也就是说加1在二进制层面来说是加了10,加2是二进制上面是加了100,这样理解才对吧?
以上是我的一些想法,有说的不对的地方,望老师不要介意 :)
文中写到 snprintf 返回值应该小于 n
但是实际测试会超过 返回格式化后的总字符长度
代码
size_t size = snprintf(s, 5, "%s%s33", "11", "22");
printf("size :>> %zu\n", size);
puts(s);
返回值
size :>> 6
1122
编译器
Apple clang version 12.0.0 (clang-1200.0.32.29)
Target: x86_64-apple-darwin19.6.0
我也查了几个文档
c 的文档好像没有详细说
https://en.cppreference.com/w/c/io/fprintf
有一个 c++的文档好像是说超过的字符会计入返回值
http://www.cplusplus.com/reference/cstdio/snprintf/
字符
*
表示指针,通常跟在类型关键字的后面,表示指针指向的是什么类型的值。比如,Char*
表示一个指向字符的指针,float*
表示一个指向float
类型的值的指针。
这里 Char*
我认为是笔误,小写 char
才是 C 语言的内置类型。
* 和 - 的优先级相同 ,它们都是左结合运算符,所以从左到右执行,先计算5 * 6,再计算6 / 2。
这里-
符号错了。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.