小编ide*_*n42的帖子

C编译器是否重复(合并)代码?

循环展开是一种常见的优化,但反过来也是如此?
(减小目标文件输出的大小,更小的二进制).

我很好奇,如果编译器将连续的,相同的代码块(或函数调用)重复数据删除到循环中,或者将重复的块提取到静态函数中,这是一种常见的技术.

我很感兴趣,因为*C中只有一些头文件库可以添加大量重复代码,所以知道一些C编译器是否能够检测到这一点并更有效地处理它会很有用.

* 通过header-only-library,我的意思是直接定义代码而不是函数定义的头.

如果这样做,那么知道在什么条件和约束下适用以确保可以使用它将是有用的.

注意(出于问题的目的 - 任何流行的C编译器都是精细的GCC/Clang/Intel/MSVC).

我找到的一个只有头文件的库叫uthash使用了一些非常大的宏,我想知道是否有一些编译器技巧可以巧妙地去除这些巨大的代码块,参见:例如uthash.h,另一个类似的示例是内联qsort.h


可以重复数据删除的块的示例(事实证明它Py_DECREF可以扩展为相当大的代码块).

#define PY_ADD_TO_DICT(dict, i)  \
    do {
        PyDict_SetItemString(dict, names[i], item = PyUnicode_FromString(values[i])); \
        Py_DECREF(item); \
    } while (0)

/* this could be made into a loop */
PY_ADD_TO_DICT(d, 0);
PY_ADD_TO_DICT(d, 1);
PY_ADD_TO_DICT(d, 2);
PY_ADD_TO_DICT(d, 3);
Run Code Online (Sandbox Code Playgroud)

请注意,这是设计的,但基于一个真实的例子.


澄清

似乎我的问题的简短答案是否定的(或仅在某些有限/微不足道的情况下),只是为了澄清我为什么要求进一步提问.

评论中的一些回复似乎假设任何人只需将代码重构为函数.当然,
几乎总是最好的选择,但有时会出现非常相似的代码块.

  • 锅炉板代码由一个非常非常智能的代码生成器创建.
  • 当使用外部API将其某些功能公开为宏时(在这种情况下,在函数中本地包装当然在大多数情况下工作,但这意味着你的代码有自己的怪癖,这对于那些API的使用来说并不常见).
  • 当你不能用函数替换宏时,有一些罕见的情况,它最终是不切实际的.
  • 当从外部代码库导入代码时,进入并开始清理代码并不总是理想的,在评估代码库时,了解编译器在优化代码时会有多聪明.

在所有这些情况下,它可以去重复(生成更智能的代码,在函数中包装宏,修补第三方库),但在努力做这些事情之前,值得知道编译器为我们做了多少工作.

c optimization compilation

14
推荐指数
2
解决办法
1201
查看次数

C找到静态数组大小(防止错误)

查找静态数组的大小是一种常见操作.看:C找到静态数组大小 -sizeof(a) / sizeof((a)[0])

这可以包装成一个宏,例如:

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

但是它可能会意外地传入常规指针.

例如: void func(SomeArray **foo) { int i = ARRAY_SIZE(foo); }

虽然它的有效C,但往往最终成为一个逻辑错误.

它可以防止这种错误(利用每个处理器在零长度位域上失败).


#define ARRAY_SIZE(a) \
    ((sizeof(struct { int isnt_array : \
     ((const void *)&(a) == &(a)[0]); }) * 0) + \
     (sizeof(a) / sizeof(*(a))))
Run Code Online (Sandbox Code Playgroud)

我发现这个宏适用于GCC,但是对于间接引用的成员,它与Clang失败了.同error: expression is not an integer constant expression

例如:

  • char word[8]; int i = ARRAY_SIZE(word); 好.
  • struct Bar { word[8]; }
    void func(struct Bar *foo) { int i = ARRAY_SIZE(foo->word); …

c arrays c-preprocessor

14
推荐指数
1
解决办法
852
查看次数

使用Cargo进行源代码构建(外部构建目录)?

使用过CMake之后,我已经习惯了使用CMake鼓励的源外构建.如何使用Cargo完成源外构建?


再次使用in-source-builds感觉就像倒退了一步:

  • 需要将开发工具配置为忽略路径.有时候有多个插件和开发工具 - 特别是使用VIM或Emacs!
  • 某些工具无法配置为轻松隐藏构建文件.虽然点文件通常是隐藏的,他们仍然会表现出Cargo.locktarget/,更糟糕的是,递归地暴露自己的内容.
  • 删除未跟踪的文件以删除版本控制之外的所有内容(通常是清理编辑器临时文件或某些测试输出),如果您忘记将新文件添加到版本控制并且在删除文件列表之前未正确手动检查文件列表,则会适得其反.
  • 依赖关系被下载到源代码路径中,有时会*.rstarget目录中添加文件作为构建间接deps的一部分,因此对所有*.rs文件进行操作可能会意外地拾取不在隐藏目录中的其他文件,因此即使在开发工具之后也不会被忽略已配置.

虽然可以解决所有这些问题,但我宁愿只有一个外部构建路径并保持源目录的原始状态.

build rust rust-cargo

14
推荐指数
1
解决办法
1710
查看次数

如何在Unix系统上直接执行Rust代码?(使用shebang)

通过阅读这个帖子,看起来可以使用shebang来运行Rust*.

#!/usr/bin/env rustc

fn main() {
    println!("Hello World!");
}
Run Code Online (Sandbox Code Playgroud)

使这个可执行文件运行并编译,但不运行代码.

chmod +x hello_world.rs
./hello_world.rs
Run Code Online (Sandbox Code Playgroud)

但是这只会将代码编译成hello_world.

可以*.rs文件可以直接执行,类似于一个shell脚本?


*这引用了rustx,我查看了这个,但是它是一个bash脚本,每次都编译脚本(没有缓存)并且永远不会从temp目录中删除文件,尽管这可以改进.它也有很大的局限性,它不能使用板条箱.

shebang rust

14
推荐指数
2
解决办法
1184
查看次数

如何在Rust中将匿名函数作为参数传递?

Rust过去一周我一直在玩弄.我似乎无法弄清楚如何在调用方法时传递一个被定义为参数的函数,并且没有遇到任何显示它们以这种方式使用的文档.

在调用函数时,是否可以在参数列表中定义函数Rust

这是我到目前为止所尝试的......

fn main() {

    // This works
    thing_to_do(able_to_pass);

    // Does not work
    thing_to_do(fn() {
        println!("found fn in indent position");
    });

    // Not the same type
    thing_to_do(|| {
        println!("mismatched types: expected `fn()` but found `||`")
    });
}

fn thing_to_do(execute: fn()) {
    execute();
}

fn able_to_pass() {
    println!("Hey, I worked!");
}
Run Code Online (Sandbox Code Playgroud)

function-pointers anonymous-function rust

13
推荐指数
1
解决办法
5080
查看次数

C函数参数,内存对齐注意事项

在C中定义结构时,有关于填充的注意事项,如果结构大小是一个问题,则通常重新排列值以避免填充.(参见:结构填料和包装)

我的问题是:

相同(或类似)的规则是否适用于函数参数?...在安排参数以避免参数填充字节方面有什么好处吗?


  • 假设这不是inline(它不重要),或者static编译器可以重新排列参数的函数.

  • 接受现实世界可衡量的改善可能很小.

...实际上,如果函数调用开销是一个问题,可能值得内联函数.尽管如此,内联并不总是一个选项(例如库或函数指针).

c function memory-alignment

13
推荐指数
1
解决办法
862
查看次数

什么是将Path转换为*c_char的最直接方法?

给定a std::path::Path,将此转换为空终止的最直接方法是std::os::raw::c_char什么?(用于传递到采用路径的C函数).

use std::ffi::CString;
use std::os::raw::c_char;
use std::os::raw::c_void;

extern "C" {
    some_c_function(path: *const c_char);
}

fn example_c_wrapper(path: std::path::Path) {
    let path_str_c = CString::new(path.as_os_str().to_str().unwrap()).unwrap();

    some_c_function(path_str_c.as_ptr());
}
Run Code Online (Sandbox Code Playgroud)

有没有办法避免这么多中间步骤?

Path -> OsStr -> &str -> CString -> as_ptr()
Run Code Online (Sandbox Code Playgroud)

string ffi rust

13
推荐指数
3
解决办法
1349
查看次数

如何在宏中添加前缀/后缀标识符?

使用定义函数的宏时,是否可以为函数添加前缀?

macro_rules! my_test {
    ($id:ident, $arg:expr) => {
        #[test]
        fn $id() {
            my_test_impl(stringify!($id), $arg);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

例如, fn my_test_$id() {

我正在使用可能以数字开头的标识符来定义测试,我想使用公共前缀.

macros rust

13
推荐指数
2
解决办法
3758
查看次数

如何反省Rust中所有可用的方法和成员?

有没有办法在Rust中打印出类型或实例的可用成员的完整列表?

如果问这个问题是Python,那么答案就是print(dir(object)).
如果问题是C,那么Clang有一个Python API可以解析C代码并对其进行内省.

不熟悉Rust工具,我很想知道是否有某种方法可以在运行时或编译时,使用编译器功能(例如宏)或使用外部工具来执行类似的操作.


请注意,这个问题是故意的,因为使用的确切方法不一定非常重要.给定一个变量,是否有办法找到它的所有方法和功能并不是一个不寻常的目标,但不能很好地了解这个领域,我不是将问题局限于特定方法.

introspection rust

13
推荐指数
3
解决办法
2212
查看次数

如何在Rust中为单个语句安静警告?

假设有一个警告,例如path_statements,unused_variables.有没有办法忽略它的一个瞬间,而不将它们隔离成代码块或函数?

需要说明的是,代码中只有一个警告.我希望能够只安静警告,而不必针对特定警告进行特殊更改.并且在其他任何地方都没有这种安静的警告,甚至在同一个功能中也是如此.

使用GCC,可以按如下方式完成:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
    /* Isolated region which doesn't raise warnings! */
    this_would_raise_Wformat(args);
#pragma GCC diagnostic pop
Run Code Online (Sandbox Code Playgroud)

Rust具有相同的功能吗?


请注意,我正在询问如何安静警告的一般情况.我知道有办法解决未使用的var警告,例如.

warnings rust

13
推荐指数
2
解决办法
1329
查看次数