我正在编写一个可以处理.c和.h文件的脚本。使用正则表达式我找到给定文件中的所有函数。在使用C语言的过程中,我总是以下列方式定义函数:
void foo(int a){
//random code
}
是否可以通过以下方式声明一个函数:
void
foo(int a){
//random code
}
我一直认为功能类型,名称和参数需要在同一行,但我已被告知,所以我并不完全确定。
答案 0 :(得分:6)
首先,你在C源代码中使用什么样的空格 - 空格,换行符,制表符等并不重要,只要有空格需要空格。此外,使用多少空白并不重要。
其次,考虑到C预处理器功能,可以将函数声明(以及其余代码)编写为
vo\
id f\
o\
o(i\
n\
t\
\
a)
(显然,预处理器可以有更多不同的方式来混淆函数定义。对于您的特定任务,最好使用已经预处理的源代码。)
第三,C仍支持K& R风格的功能定义,如下所示
void foo(a)
int a;
{
...
}
答案 1 :(得分:5)
C是一种自由形式的语言;通常,除了单独的令牌外,空格并不重要。 (对于该断言有一些警告,特别是在预处理程序指令中,以及字符串文字和字符文字内部,但通常是准确的。)因此,以下是一个可怕但合法的C函数定义:
/* Comment before the type */ SomeUserDefinedTypeName
/??/
* comments, with trigraphs to boot
*??/
/
FunctionName
(
SomeType param1,
AnotherType
(
*
param2
)
[
]
)
/\
/ one line comment
// another line comment \
yes, this is part \
of that one-line comment too
{
...
}
当然,任何产生这样功能的人都应该被挂起,抽出和四分之一 - 或者至少受到严厉批评 - 但是你必须决定你想要代码的通用程度。如果它需要与任何C一起使用,你需要像这样处理c ** p 1 。另一方面,你可能可以通过更复杂的解析来逃避。
1 有一个A和一个R缺失,我不是在谈论鱼。
答案 2 :(得分:4)
这是一个名为test
的有效C函数,它将一个const指针带到void(名为ptr)并返回一个指向函数的指针,该函数接受一个返回int的函数的五个指针数组并返回一个unsigned int。
unsigned int (*(test)(const void *ptr)) (int (*[5])())
{
return 0;
}
(如果有人可以找到真实世界的情况,这个东西可以有用),奖励积分
虽然已弃用,但您也可能会接触旧式"功能表示法:
// declaration
unsigned int test2();
// definition
unsigned int test2(ptr)
const void *ptr;
{
return 0;
}
混合在这里你可以找到评论(自C99以来的多行和单行),三字母甚至宏:
#define defun(fn) fn (
#define fstart ){
#define fend }
void defun(test3) int a, double b
fstart
printf("%d %f", a, b);
fend
即使排除病态宏观情景,"普通"正则表达式甚至不能开始解析这个东西,因为它们不能匹配括号;也许你可以用扩展的正则表达式做点什么,但说实话,你真的想要应付这些东西吗?使用现成的解析器甚至编译器(libclang
会想到)并让它完成脏工作。
答案 3 :(得分:1)
我认为对于初学者用户从零开始编写使用正则表达式来解析源代码的代码是非常困难的,但它也可能效率很低。
正如我之前所说,我建议使用像pyparsing这样写得很好的库,它可以让您将语言的BNF符号转换为库的特定对象。
在定义了使用pyparsing API编写的解析元素之后,您也可以使用库轻松地解析简单字符串或复杂文件。 在第一时刻可能有点困难,但我认为你可以很容易地使用它有很好的结果。
我建议您查看使用pyparsing库定义的simple C grammar。它编写得很好并且有文档记录。
答案 4 :(得分:0)
因此,空格包括制表符,换行符和空格等字符。
通常,这些空白字符是可以互换的。也就是说,你可以用换行符替换每个空格(反之亦然),编译器也不会关心。
有几个地方专门处理换行。我想到的一些包括预处理器,字符串文字,字符文字和单行注释。
通过您展示的两个示例,两者都被解析相同。另外,我们也可以把它写成:
void
foo (
int
a
) { //random code
}
或:
void
foo
(
int
a
)
{
//random code
}
或:
void foo(int a){ /* random code */ }
答案 5 :(得分:0)
这两个都是正确的(将编译),因为C编译器将忽略返回类型和函数名之间的空格。函数定义的格式通常是:
<return type> <function name> (<parameter list>) {
<body>
}
在编译期间,返回类型和函数名称是单独的标记,解析器将忽略它们之间的空格。希望这会有所帮助。