- 博客(56)
- 收藏
- 关注
原创 【看到哪里写到哪里】C的“数组指针”
其实,还是要清楚指针的基本概念:它是指向一个内存地址的数值!它的增加和减少的位移,是由它的数据类型决定的。C里面,数组指针,不是基本类型。顾名思义,数组指针,是。2.数组指针的定义和初始化。1.它的基本定义样子是。3、一个二维数值的例子。
2025-06-07 18:37:50
382
原创 【看到哪里写到哪里】C的指针-4(字符串常量)
字符串指针是以字符为单位的,那它+1,就是指向指针的下一个字符位置,那就是它指向字符串中第二个字符B。当一个字符串常量出现在表达式的时候,它的值就是一个指针常量。编译器会把这些字符的copy存储在内存中的某个位置,并存储一个指向第一个字符的指针。我们可以理解了,字符串指针在做间接访问操作,对一个指针的*操作,就是取该指针所指的位置的值,那就是"A"了!按照我们对字符串的理解,很容易就是说一个指针在做下标运算,那它的结果就是字符“C”这个就是先做字符串常量指针运算(+1),然后取该位置的值,那就是"B"!
2025-06-03 00:33:41
185
原创 【看到哪里写到哪里】C的指针-3(函数指针)
注:这里的【"+-*/"[i]】,其实也是指针应用,回头单独讨论。这个例子,对理解函数指针和指针函数,有基础的、实际的意义。4、做四个计算,输出结果内容;,赋值成四个函数的地址;上面是一个简单的例子,
2025-06-03 00:06:08
380
原创 【看到哪里写到哪里】在C里面怎么传递二维数组呢?
在 C 语言中,传递二维数组作为函数参数时,需要确保函数能够正确解析数组的内存布局。由于 C 语言的二维数组在内存中是连续存储的(按行优先),因此。最直接的方式是在函数参数中明确指定二维数组的列数。通过指向数组的指针传递,更清晰地表达参数类型。
2025-06-02 23:14:55
159
原创 【看到哪里写到哪里】a+++b 怎么算呢?
但是a++返回的是数值,而不是左值,所以。编译器会告诉你:错了!这又牵涉到a++计算顺序:它先贡献自身的值,然后再做++的预算。另外 a ++ ++ + b,这次有个+号?它的情况会怎么样呢?另外 (a++) 返回的是10,而不是++之后的值11呢?:C 语言编译器从左到右尽可能多地组合字符,因此。C的运算符顺序是很有意思的。尤其++/--的使用。即编译器会尽可能多地组合字符形成合法的运算符。它肯定拆分成 [ (a++) ++] + b。的优先级不同,但此处的关键是。在 C 语言中,表达式。
2025-06-02 23:06:42
397
原创 【看到哪里写到哪里】C的指针-2(函数指针)
但是在程序的执行过程中,函数名f首先被转换成一个函数指针,该指针指向函数在内存中的位置,然后调用的时候,调用该函数,执行开始于这个地址的代码;调用2:对pf执行间接操作,把函数指针转换成一个函数名,然后编译器在执行函数调用符之前,又会把它转换回去成函数指针,指向函数的位置;&写出来,是显式地说明了赋值的是函数的地址。然后定义一个函数指针pf,给它做初始化,赋值为函数f的地址 (&f)所以这里省掉&,也是可以对函数指针初始化化的!在这里,初始化的是时候,没使用&,可以么?1、函数指针的一个简单的定义和使用。
2025-05-31 00:15:12
110
原创 【看到哪里写到哪里】C的指针-1
这里说明,也是一个函数的声明,返回的是int型的指针;后面的声明中,g是一个函数指针数组,数组的元素类型是函数指针,指向的函数都还有两个int参数,返回值也是int;这个,看着是一个int数组,其中f应该是一个函数。其实,它也是错的,数组的元素肯定是相同的,但是这里的函数很有可能不是相同的类型/长度;它是说f是一个函数指针,指向一个函数,该函数的返回值,是一个int的指针哦;f是一个函数指针数组,数组的元素都是函数,返回值是int指针的函数;f是一个函数指针数组,它数组的元素是函数,返回值为int的函数;
2025-05-30 23:24:29
148
原创 VSCode编译时错误:Invalid argument. 是因为新版MSYS2 默认禁用通配符支持
查了半天,是因为刚升级了MSYS2。因为从 2024 年 11 月 3 日开始,MSYS2 默认禁用通配符支持。此更改会影响在生成命令中处理通配符的方式。要在 中构建多个 C++ 文件,您必须明确列出这些文件。编译原来可以正常编译的C程序时,报错“*.c: Invalid argument”所以在Tasks.json文件中要把.c文件一个个的罗列出来,不能再用*.c代替。
2025-05-14 21:01:58
297
原创 C语言标准的发展
The Standard - C ISO/IEC 9899:2024 - Information technology — Programming languages — Chttps://www.iso.org/standard/82075.html
2025-05-12 20:50:11
219
原创 C预编译器-43(环境变量)
DEPENDENCIES_OUTPUT 的值可以只是一个文件名,在这种情况下,Make 规则将被写入该文件,并从源文件名猜测目标名称。或者,值可以有 ‘file target’ 的形式,在这种情况下,规则将被写入到 file 文件中,使用 target 作为目标名称。每个变量的值是一个由特殊字符分隔的目录列表,类似于 PATH,用于查找头文件。您可以使用它们来指定在搜索包含文件时使用的目录或前缀,或者控制依赖项输出。该值应为已知的时间戳,如源代码或软件包的最后修改时间,并且应由构建过程设置。
2025-05-03 17:48:37
250
原创 C预编译器-42(调用3 Invocation)
如果宏实际上被使用,但仅在被跳过的条件块中使用,则预处理器会报告它为未使用。例如,出现在可能成为指令行开头的注释会产生将该行变为普通源代码行的效果,因为行的第一个标记不再是。覆盖系统头文件,用您自己的版本替代,因为这些目录会在标准系统头文件目录之前被搜索。,但仅输出那些被展开的宏,或在预处理指令中测试其定义状态的宏;所有注释都会被传递到输出文件中,但处理指令中的注释除外,这些注释会随着指令一起被删除。指令,包括预定义的宏。尝试模仿早期的非标准 C 预处理器的行为,而不是 ISO C 预处理器的行为。
2025-04-29 11:30:21
756
原创 C预编译器-41(调用2 Invocation)
启用此选项后,预处理器会在初始行标记之后发出第二个行标记,其中包含当前工作目录,后面跟随两个斜杠。GCC 在预处理输入中存在此目录时,将其作为某些调试信息格式中发出的当前工作目录。设置输入字符集,用于从输入文件的字符集转换为 GCC 使用的源字符集。如果区域设置未指定,或者 GCC 无法从区域设置获取此信息,则默认值为 UTF-8。这允许编译器在宏展开中发生编译错误时,发出当前宏展开堆栈的诊断信息。将绝对路径更改为相对路径,从而实现更可重现的构建,且与位置无关。在预处理时,仅处理指令,但不展开宏。
2025-04-29 11:29:01
798
原创 C预编译器-40(调用 Invocation)
在GCC中,预处理器实际上是与编译器集成在一起的,并不是一个单独的程序,这两个命令都会调用GCC并告诉它在预处理阶段后停止。如果您是从 shell 或类似 shell 的程序调用预处理器,则可能需要使用 shell 的引号语法来保护具有特殊含义的字符(如空格)。更改依赖生成发出的规则的目标。的第一个目录是预处理器的工作目录,而不是包含主源文件的目录。,但不会提及在系统头文件目录中找到的头文件,也不会提及直接或间接从这些头文件中包含的头文件。否则,它会取输入文件的名称,移除任何目录组件和后缀,并应用。
2025-04-28 08:55:04
834
原创 C预处理器-39(实现细节)
以下是CPP在C标准中描述为“实现定义”的所有情况下的行为。术语“实现定义”意味着实现可以自由选择其行为,但必须记录其选择并始终遵循。物理源文件的多字节字符到执行字符集的映射输入字符集可以通过选项指定,而执行字符集可以通过和选项控制。标识符字符C 和 C++ 标准允许标识符由下划线()和字母数字字符组成。C++ 还允许通用字符名(universal character names)。C99 及更高版本的 C 标准允许通用字符名和实现定义的字符。
2025-04-28 08:54:22
1057
原创 C预编译器-35(编译指示Pragmas)
是 C 和 C++ 标准中定义的一种编译指示,用于向编译器提供额外的指令或信息。如果中毒的标识符作为定义在中毒之前定义的宏扩展的一部分出现,则不会导致错误。指令是 C 标准指定的向编译器提供语言本身无法传达的额外信息的方法。如果这些标识符中的任何一个出现在指令之后的源代码中的任何位置,则会产生严重错误。此编译指示不带参数。这可以帮助确保配置文件是最新的,从而避免因文件版本不一致导致的问题。的一个主要问题:作为一个指令,它不能作为宏扩展的结果产生。可以帮助管理头文件的包含次数,防止重复包含导致的编译错误。
2025-04-23 00:52:32
909
原创 C预处理器-34(行控制)
如果您编写一个生成源代码的程序,例如 bison 解析器生成器,您可能希望手动调整预处理器对当前文件名和行号的概念。bison 的输出部分是从头开始生成的,其他部分来自标准解析器文件,剩余部分则是从 bison 的输入中逐字复制的。是 C 预处理器的一个指令,用于控制编译器报告的源代码文件名和行号。在这种情况下,如果出现编译错误,直接指向生成后的文件可能会让开发者困惑。是一个指定当前预处理器输入文件中后续输入的原始行号和源文件名的指令。指令,可以让编译器和调试器正确地引用原始输入文件,从而方便调试。
2025-04-22 00:13:18
830
原创 C预处理器-33(诊断)
都不会对它们的参数进行宏展开。内部的空白字符序列会被替换为单个空格。最明智的做法是将这些指令的参数设置为单个字符串常量;这可以避免与撇号等字符相关的问题。如果您有几个配置参数需要安装时以一致的方式设置,可以使用条件编译来检测不一致性,并通过。您可以在检测到一组参数组合(这些参数组合是程序无法正确支持的)的条件编译中使用。,并在其中添加一条消息,指导用户使用应该替代它的头文件。,但它会导致预处理器发出警告并继续预处理。后面的行中剩余的标记将被用作错误消息。后面的标记将被用作警告消息。
2025-04-22 00:12:36
179
原创 C语言最新标准 – ISO/IEC 9899:2024 (C23)
The current standard for the programming language C is ISO/IEC 9899:2024 – Information technology – Programming languages – C.
2025-04-21 00:20:53
1997
原创 C预处理器-32(删除代码)
注释中常常包含不成对的单引号字符(在英语中称为撇号)。即使被关闭的代码中包含条件编译指令,这种方法也有效,但这些条件编译指令必须是完整的(即匹配的。如果您替换或删除程序的一部分,但希望保留旧代码以供将来参考,通常不能简单地将其注释掉。避免此问题的一种方法是使用一个始终为假的条件编译指令。例如,在被删除的代码前加上。)不能嵌套,因此旧代码中的第一个注释会结束注释块,结果很可能是大量的语法错误。用于非 C 代码的注释。相反,应该使用真正的注释(如。可能意外被定义为宏,这样条件编译就会成功。
2025-04-21 00:18:59
120
原创 C预处理器-31(特殊操作符)
因此,将两个测试合并为单个表达式(如下所示)仅在支持该操作符的编译器上有效,而在不支持该操作符的编译器上则无效。因此,将两个测试合并为单个表达式(如下所示)仅在支持该操作符的编译器上有效,而在不支持该操作符的编译器上则无效。操作符(没有操作数和括号)时,它会充当一个预定义宏,以便在可移植代码中测试对其的支持情况。操作符(没有操作数和括号)时,它会充当一个预定义宏,以便在可移植代码中测试对其的支持情况。的整型常量,表示该属性首次被引入 C 标准的年份和月份,或者该属性的操作数语法在 C 标准中扩展的时间。
2025-04-21 00:18:01
1133
原创 C预处理器-30(#elif)
嵌套条件编译的一种常见用法是用来检查超过两种可能的选项。类似,它位于条件编译组的中间,并将其细分为多个部分;它不需要单独匹配一个。指令包含一个需要测试的表达式。在同一个条件编译组中可以有多个。表示“else if”。后面的文本才会被处理。后面的文本仅在原始的。条件成功时才会被处理。
2025-04-20 00:04:09
111
原创 C预处理器-29(defined、#else)
操作符是由于宏展开而出现的结果,C 标准表示这种行为是未定义的。GNU cpp 将其视为一个真正的。,它会在代码使用此功能的地方发出警告,因为其他编译器可能对此处理方式不同。指令可以添加到条件编译中,以在条件失败时提供替代文本。被定义为宏,则它们的值为 1,否则为 0。操作符并正常对其进行求值。如果您使用命令行选项。表达式中,以测试某个名称是否被定义为宏。中的任何一个被定义为宏,该条件就会成功。都是表达式,如果在程序的当前点上。当您希望同时测试多个宏是否存在时,未定义,它会被解释为值为零。
2025-04-20 00:03:32
197
原创 C预处理器-28(#ifdef、#if)
在 GCC 支持的大多数机器上,这是 64 位。这与编译器用于计算常量表达式值的规则不同,在某些情况下可能会导致不同的结果。因此,它在词法上必须是有效的 C 语言代码。通常唯一需要注意的是,在失败的条件组中的所有注释和字符串字面量仍然需要正确结束。后面的注释不是必需的,但如果受控文本较多,这是一个好的实践,因为它帮助人们将。指令允许您测试一个算术表达式的值,而不仅仅是检查某个宏的存在。是一个整数类型的 C 表达式,但受到严格的限制。此外,不能在一个文件中开始一个条件组而在另一个文件中结束它。
2025-04-19 17:22:57
966
原创 C预处理器-27( 条件编译)
它的目的是根据程序操作的数据,在不同的运行中让程序表现出不同的行为。而预处理器条件编译指令中的条件是在程序编译时进行测试的。它的目的是根据编译时的情况,将不同的代码包含到程序中。当然,您只能用这种方式排除代码,而不能排除类型定义或其他预处理指令,并且只有在代码在未被使用时仍然保持语法有效性的情况下才能这样做。条件始终为假的条件编译是一种从程序中排除代码但仍然将其作为某种注释保留的方法,以供将来参考。简单的程序通常不需要使用系统特定的逻辑或复杂的调试钩子,因此一般不需要使用预处理条件编译指令。
2025-04-19 16:47:52
416
原创 C预处理器-26(自引用宏、参数预扫描、参数中的换行符)
当一个宏的参数中包含了对该宏本身的调用时,我们称之为宏的嵌套调用。没有预扫描的话,f(1) 本身将作为参数被替换,内部使用的 f 在主扫描期间将被视为间接自引用并不会被展开。您可能会认为当自引用宏作为另一个宏的参数使用时(参见自引用宏),双重扫描会改变结果:自引用宏会在第一次扫描时展开一次,在第二次扫描时再展开一次。如果宏 x 展开使用了宏 y,而 y 的展开又引用了宏 x,这就是 x 的间接自引用。每当一个宏出现在另一个宏的定义中时,该宏会被展开,但是当它间接出现在自己的定义中时,则不会被展开。
2025-04-19 16:38:34
643
原创 C预处理器-25( 吞掉分号的问题、副作用的重复计算)
局部变量的名字后面带有下划线,以减少与更广泛作用域中的标识符发生冲突的风险(完全避免冲突是不可能的)。严格来说,这个调用会展开为一个复合语句,它是一个完整的语句,不需要用分号来结束。这里使用了反斜杠换行符来分割宏定义,尽管宏定义在逻辑上必须是一行,但这样可以让它看起来像是非宏代码的布局方式。之间存在两条语句——一条是复合语句,另一条是空语句——这会导致无效的 C 代码。通常,我们希望定义一个展开为复合语句的宏。有副作用,或者它的计算耗时较长,结果可能与预期不符。的值,将其保存在一个变量中,然后在。
2025-04-19 16:33:03
310
原创 C预处理器-24(错层嵌套、运算符优先级)
当一个宏被调用并传入参数时,这些参数会被替换到宏体中,随后生成的结果会与输入文件的其余部分一起被检查,以寻找更多的宏调用。在这种过程中,可以将部分来自宏体和部分来自参数的内容拼接成一个新的宏调用。您可能已经注意到,在上面展示的大多数宏定义示例中,每个宏参数名称的每次出现都带有括号。宏定义并不需要具有平衡的括号。通过在宏体中写入一个未闭合的左括号,可以创建一个从宏体内部开始但结束于宏体外部的宏调用。这种拼接宏调用的能力有时可能会很有用,但在宏体中使用不平衡的左括号只会让人感到困惑,因此应该避免使用这种方式。
2025-04-19 16:24:09
180
原创 C预处理器-23(宏的陷阱概述)
宏是一种强大的工具,但由于其基于文本替换的本质,可能会引发许多难以察觉的问题。嵌套错误:确保宏定义和调用的结构正确。运算符优先级:使用括号明确表达式的优先级。分号问题:避免宏吞掉分号,推荐使用封装复杂逻辑。副作用重复:避免在宏中多次使用具有副作用的参数。自引用宏:避免宏直接引用自身,防止递归展开。参数预扫描:了解参数在宏展开前会被预扫描的行为。换行符问题:尽量避免在宏参数中使用换行符。通过理解这些陷阱并采取适当的预防措施,可以更安全地使用宏来编写高效且可靠的代码。
2025-04-19 16:09:24
363
原创 C预处理器-22(取消定义和重新定义宏、宏参数中的指令)
如果一个宏不再有用,可以使用#undef指令取消定义它。#undef接受一个参数,即要取消定义的宏名称。即使宏是函数式的,你也只需使用宏的基本名称即可。如果在宏名称之后的行上出现任何内容,则会报错。如果指定名称不是一个宏,#undef不会产生任何效果。cx = FOO;// x = 4;// x = FOO;此时 FOO 未定义,可能导致编译错误或警告一旦一个宏被取消定义,该标识符可以通过后续的#define指令重新定义为一个宏。新的定义不必与旧定义有任何相似之处。
2025-04-19 16:06:49
579
原创 C预处理器-21(C++ 命名运算符Named Operators)
C++ 提供了十一个命名运算符作为传统标点符号运算符的替代写法。这些命名运算符在预处理器中仍然被视为运算符,无法被重新定义或毒化。在 C 中,可以通过包含iso646.h头文件来启用这些命名运算符。虽然这些命名运算符提高了代码的可读性,但在现代代码中并不常用,建议根据团队编码风格选择是否使用。
2025-04-19 16:06:35
272
原创 C预处理器-20(系统特定的预定义宏)
对于所有这样的宏,GCC 提供了一个带有双下划线前缀和后缀的平行宏。由于本手册面向所有系统和机器,无法列出它们的具体名称,但你可以使用 cpp -dM 命令查看所有这些宏。所有系统特定的预定义宏都会扩展为一个常量值,因此你可以使用 #ifdef 或 #if 对它们进行测试。我们也不建议你使用那些位于保留命名空间中的系统特定宏。当给编译器传递 -ansi 选项,或任何请求严格符合标准的 -std 选项时,所有不在保留命名空间中的系统特定预定义宏都会被禁用,而位于保留命名空间中的平行宏仍然保持定义状态。
2025-04-19 16:05:55
134
原创 C预处理器-19(常见预定义宏)
常见的预定义宏是GNU C的扩展。无论您是在哪种机器或操作系统上使用GNU C或GNU Fortran,它们都具有相同的含义。它们的名字都以双下划线开头。
2025-04-19 16:04:37
1011
原创 C预处理器-18(标准预定义宏)
在正常操作中,该宏扩展为常量 1,表示该编译器符合 ISO 标准 C。虽然我们称它为预定义宏,但它是一个非常特殊的宏,因为它的“定义”会随着每一行新代码的变化而变化。标准预定义宏由相关的语言标准指定,因此所有实现这些标准的编译器都支持它们。该宏扩展为当前输入文件的名称,形式为 C 字符串常量。该宏扩展为描述预处理器运行日期的字符串常量。如果编译器的目标是托管环境,则定义该宏,值为 1。根据所选的语言标准,宏的值为:1998 年 C++ 标准为。当使用 Objective-C 编译器时,定义该宏,值为 1。
2025-04-18 14:29:59
606
原创 C预处理器-17(预定义宏分类)
有几个类对象宏是预定义好的;你无需提供它们的定义就可以使用。标准预定义宏常见预定义宏和特定于系统的预定义宏。在 C++ 中,还有第四类,即命名运算符。它们的作用类似于预定义宏,但你不能取消对它们的定义。标准预定义宏常见预定义宏特定于系统的预定义宏C++ 命名运算符。
2025-04-18 14:23:59
126
原创 C预处理器-16(可变参数宏)
(请注意,这一限制在 C++20 中已被取消,并且在 GNU C 中从来就不存在这样的限制,详见下文。标准对此规定不明确。对于只有一个可变参数参数作为宏参数的情况,上述解释存在歧义,因为试图区分完全没有参数是属于空参数还是缺失参数是没有意义的。当调用这个宏时,其参数列表中在最后一个已命名参数(这个宏没有已命名参数)之后的所有标记,包括任何逗号,都将成为可变参数。此外,如果你将可变参数留空,就会得到一个语法错误,因为在格式字符串之后会有一个多余的逗号。在可变参数宏中,你既可以有已命名参数,也可以有可变参数。
2025-04-18 14:20:50
339
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人