C程序字符串解析

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

我正在将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 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
}