You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Coccinelle修改结构体名称为小写时遇属性错误求助

如何用Coccinelle将结构体typedef名称转换为Linux内核编码风格

我尝试用Coccinelle批量修改C代码的结构体typedef名称为Linux内核风格,但遇到了AttributeError: Cocci instance has no attribute 'make_type'的错误,下面是我的问题详情和解决方案:

问题背景

我想要将驼峰式的结构体typedef名称(比如strName)转换为下划线分隔的小写风格(比如str_name),示例代码转换目标如下:

原始代码:

typedef struct {
    char me;
    long you;
} strName;
int main (void) {
    strName *DeV;
    return 0;
}

期望转换后代码:

typedef struct {
    char me;
    long you;
} str_name;
int main (void) {
    str_name *DeV;
    return 0;
}

我编写了如下Coccinelle脚本,但运行时报错:

原始Coccinelle脚本:

@rule1 disable all@
type t;
@@
typedef struct { ... } t;

@ script:python foo @
t_fixed; var; t << rule1.t;
@@
import re
def split_uppercase(s):
    return re.sub(r'([a-z-0-9])((?<![0-9]{4})[A-Z])',r'\1_\2',s).replace("_k_Hz", "_kHz").replace("_M_Hz", "_MHz").replace("d_B", "dB").lower()
print coccinelle.t
coccinelle.t_fixed = split_uppercase(t)
print coccinelle.t_fixed
coccinelle.var = cocci.make_type(t_fixed)
print var

@rule2 disable all@
type rule1.t; type foo.var;
@@
+ var
- t

错误信息

运行脚本时出现以下错误:

init_defs_builtins: /usr/lib/coccinelle/standard.h
-----------------------------------------------------------------------
processing semantic patch file: structs_test.cocci
with isos from: /usr/lib/coccinelle/standard.iso
-----------------------------------------------------------------------
dependencies for script satisfied:
HANDLING: test_basic.c
dependencies for rule rule1 satisfied:
transformation info is empty
dependencies for script satisfied:
Traceback (most recent call last):
  File "<string>", line 10, in <module>
AttributeError: Cocci instance has no attribute 'make_type'
while running simple python string:
from coccinelle import *
import re
def split_uppercase(s):
    return re.sub(r'([a-z-0-9])((?<![0-9]{4})[A-Z])',r'\1_\2',s).replace("_k_Hz", "_kHz").replace("_M_Hz", "_MHz").replace("d_B", "dB").lower()
print coccinelle.t
coccinelle.t_fixed = split_uppercase(t)
print coccinelle.t_fixed
coccinelle.var = cocci.make_type(t_fixed)
print var
: Failure in foo
Fatal error: exception Yes_pycocci.Pycocciexception

解决方案

错误的根源是cocci.make_type并不是PyCoccinelle提供的有效API函数。我们不需要创建“类型对象”,只需要将处理后的字符串直接赋值给var即可——Coccinelle会自动将这个字符串识别为类型名称用于替换。

修正后的Coccinelle脚本

@rule1 disable all@
type t;
@@
typedef struct { ... } t;

@ script:python foo @
t_fixed; var; t << rule1.t;
@@
import re
def split_uppercase(s):
    return re.sub(r'([a-z0-9])((?<![0-9]{4})[A-Z])', r'\1_\2', s)\
           .replace("_k_Hz", "_kHz")\
           .replace("_M_Hz", "_MHz")\
           .replace("d_B", "dB")\
           .lower()
coccinelle.t_fixed = split_uppercase(t)
coccinelle.var = coccinelle.t_fixed

@rule2 disable all@
type rule1.t; type foo.var;
@@
+ var
- t

关键修改说明

  1. 移除了错误的cocci.make_type(t_fixed)调用,直接将处理好的t_fixed字符串赋值给var
  2. 移除了调试用的print语句,让脚本更简洁(如果需要调试可以重新添加)
  3. 调整了正则表达式中的[a-z-0-9]为[a-z0-9](避免误匹配连字符,若你的代码中有带连字符的类型名可以保留原表达式)

额外优化:匹配所有类型引用

如果想要同时修改代码中所有使用该类型的地方(比如示例中的strName *DeV;也需要改成str_name *DeV;),可以扩展规则,让rule1不仅匹配typedef定义,还能匹配类型的使用:

@rule1 disable all@
type t;
identifier obj;
@@
// 匹配typedef定义
typedef struct { ... } t;
// 匹配类型的变量声明
t obj;

@ script:python foo @
t_fixed; var; t << rule1.t;
@@
import re
def split_uppercase(s):
    return re.sub(r'([a-z0-9])((?<![0-9]{4})[A-Z])', r'\1_\2', s)\
           .replace("_k_Hz", "_kHz")\
           .replace("_M_Hz", "_MHz")\
           .replace("d_B", "dB")\
           .lower()
coccinelle.t_fixed = split_uppercase(t)
coccinelle.var = coccinelle.t_fixed

@rule2 disable all@
type rule1.t; type foo.var; identifier rule1.obj;
@@
// 替换typedef定义中的类型名
+ var
- t
// 替换变量声明中的类型名
+ var
- t
  obj;

这个优化后的脚本会同时修改typedef定义和所有使用该类型的变量声明,完全符合Linux编码风格的转换需求。

内容的提问来源于stack exchange,提问作者curious_penguin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:04:52