C程序字符串解析
我正在将Makefile中的宏定义解析为两个字符串,即宏的名称和主体。例如,下面是我的Makefile中的宏定义行: 宏-1=体-1 我的代码产生总线错误/分段错误C程序字符串解析,c,string,parsing,segmentation-fault,C,String,Parsing,Segmentation Fault,我正在将Makefile中的宏定义解析为两个字符串,即宏的名称和主体。例如,下面是我的Makefile中的宏定义行: 宏-1=体-1 我的代码产生总线错误/分段错误 static void parse_macro_def(const char* line) { char* m_name; int name_pos = 0; int i = 0; while(line[i++] != '=') //iterate until an e
static void parse_macro_def(const char* line)
{
char* m_name;
int name_pos = 0;
int i = 0;
while(line[i++] != '=') //iterate until an equal sign is found
{
if(!isspace(line[i])) //copy characters to m_name unless the character is whitespace
{
m_name[name_pos++] = line[i];
}
}
}
m_name[name_pos] = '\0';
m_name应设置为macro-1
谢谢你的帮助 您不初始化
m_name
,所以它指向任何地方,所以您随机编写,并且崩溃
您需要分配并返回空间,或者传入空间(以及空间的长度),以确保不会在任何情况下覆盖
您应该注意,宏名称中的空白字符是宏定义中的一个错误。可以有引导空白;可以有尾随空白;但是在名称的中间不能有空白。现在,如果您假设您得到了一个有效的、正在工作的
Makefile
来解析,那么您可能可以忽略这个微妙之处。如果您正在为make
编写替换文件,则不能
除非您之前已验证字符串中是否有等号,否则还应检查是否没有从字符串结尾处跑掉(您没有扫描过NUL'\0'
)。事实上,在健壮的代码中,您可能会出于偏执而确保这一点
while (line[i] != '\0' && line[i] != '=')
{
...
}
在写这篇文章的过程中,我意识到在while
条件中增加I
,然后检查下一个字符是否是循环体中的空格。我们可以说,这有点传统。如果遇到宏:
MACRO=value
当循环条件检查O
时,您将=
复制到m_name
。而且,AFAICS,您不会复制M
请注意,您的线路:
m_name[name_pos] = '\0';
在任何函数之外,因此出现语法错误。
m_name
不确定,您尚未为其分配任何值。您可能希望将调用的返回值分配给malloc
或calloc
此外,如果行中不包含
=
,则循环的读数将超过行尾。您需要确保循环到达=
或行尾(可能是'\n'
或'\0'
,具体取决于您的需要)后终止。代码中存在一些缺陷,例如,您永远不会检查/复制行中的第一个字符(因为您会立即增加i
)。此外,m_name
没有指向任何地方(未定义)
总的来说,我会使用一些不同的方法。我不确定您希望在何处使用空格,但是现在(假设您的代码可以工作)您正在连接所有内容,例如,“some value=something”(我知道这不是有效的代码)将由于跳过所有空格字符而导致变量名为“somevalue”
我会使用类似的方法(时间很晚了,我很困,所以可能会包含一些bug,但应该会让您了解可以尝试做什么):
字符名[256];
常量字符*开始=行;//指向行的开头
常量字符*end=strchr(行“=”);//返回一个指针,指向有等号的位置(如果有;否则为0)
if(end){//仅当有等号时才尝试解析
对于(;startstart&&isspace(*(end-1));--end);//这将有效地删除所有尾随空格字符
strncpy(name,start,end-start);//复制名称
//在这里做点别的
}
另外,根据您在其他部分中要做的事情,使用某种正则表达式库(如果增加的开销值得,则取决于您的项目)和一些表达式(如
\s*(*))可能会很有用\s*=
如果行中不包含=
符号,则可能会产生分段错误。此外,您没有为m_name
分配任何空间,指针值不确定,这意味着它指向您可能不希望它指向的某个位置。请使用strtok()
,让你的生活更轻松。@BrianRoach:如果输入是const char*
,那么strtok
只有在复制到一个新的、可修改的缓冲区后才能工作,或者通过将原始的“API契约”更改为char*
@dreamlax-我的意思是他完全改变了方法,因为他是定义“API合同“在某种程度上重新发明轮子;)我假设m_name
超出范围是一个输入错误,考虑到他成功地编译了它并获得了SEGFULTS。@dreamlax:我认为这意味着我们没有看到失败的确切代码,因此我们没有真正的方法来可靠地帮助他。我们可以指出显而易见的,但仅此而已。谢谢!!我的解析工作,m_名字超出范围是一个输入错误。另外,我以前验证过字符串中有一个等号;这是确定makefile中的一行实际上是宏的很大一部分。
char name[256];
const char *start = line; // points to beginning of the line
const char *end = strchr(line, '='); // returns a pointer to the position where there's an equal sign (if there's any; 0 otherwise)
if (end) { // only try to parse if there's an equal sign
for(; start < end && isspace(*start); ++start); // this will effectively remove all leading space characters
for(; end > start && isspace(*(end - 1)); --end); // this will effectively remove all trailing space characters
strncpy(name, start, end - start); // copy the name
// do something else here
}