使用Visual C ++将函数标记为无副作用

时间:2013-09-16 15:25:48

标签: c++ visual-c++ side-effects restrict-qualifier

考虑以下(有点构思)示例:

// a.cpp
int mystrlen(const char* a) {
   int l = 0;
   while (a[l]) ++l;
   return l;
}

// b.cpp
extern int mystrlen(const char*);
int foo(const char* text) {
   return mystrlen(text) + mystrlen(text);
}

能够告诉编译器mystrlen()没有副作用,因此它可以重用mystrlen(text)的旧结果而不是两次调用它,这将是非常好的。

我在文档中找不到任何关于它的内容,restrict或其中一个差异似乎也没有完成任务。查看所有优化的输出代码(switch /Ox)表明编译器确实生成了两个调用。如果我将两个函数放在一个模块中,它甚至会这样做。

任何解决方案或任何人都可以确认VC ++中没有解决方案吗?

3 个答案:

答案 0 :(得分:0)

MSVC不支持pure / const属性,也无意支持它们。见https://connect.microsoft.com/VisualStudio/feedback/details/804288/msvc-add-const-and-pure-like-function-attributes。其他编译器,如GCC和Clang确实支持这些属性。另请参阅pure/const function attributes in different compilers

答案 1 :(得分:0)

您正在寻找的东西不会帮助您。

通常,编译器不能忽略调用,即使认为函数没有副作用也是如此。你从哪里得到那个指针?信号处理程序是否可以访问同一个指针?也许另一个线程?编译器如何知道指针所指向的内存是不是要从它下面改变?

编译器经常消除函数体内的冗余提取,即使对于通过指针提取的事物也是如此。但是他们可以甚至应该做多少这样做是有限的。

在这里,您要求编译器相信您必须知道哪个裸指针知道哪里将在两个函数调用之间保持一致的内容。这是很多假设。当然你还没有宣布你的指针易变,但是,它仍然是很多假设。

现在,如果你在堆栈上有一个缓冲区并且连续两次将它传递给该函数,那么编译器可以非常安全地假设如果你还没有将指针传递到其他地方,那么在某个意外的时间,缓冲区不会被程序中的一些随机的东西改变。

例如:

// b.cpp
extern int mystrlen(const char*);
int foo(int bar) {
   char number[20];
   snsprintf(number, 20, "%d", bar);
   return mystrlen(number) + mystrlen(number);
}

假设编译器可以假设snprintf numbermystrlen做了什么,假设它具有库函数,那么如果有mystrlen,它可能会忽略<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-scratchpad</artifactId> <version>3.0.1-FINAL</version> </dependency> 的第二次调用声明String sql1 =("update colo set " + x + " = ? where id = ?");//no single quote for x pstmt = conn.prepareStatement(sql1); pstmt.setString(1, num_1); pstmt.setString(2, i); int r = pstmt.executeUpdate(sql1); 没有副作用的方式。

答案 2 :(得分:-1)

因为C ++是一种命令式语言而不是功能性语言,所以你想要达到的目标是不可能的。

看起来你期望的行为就是引用透明性,在C ++中没有办法告诉编译器(但是像Haskell这样的纯函数式编程语言是隐含的)。

希望未来的C ++标准会引入一个关键字,使我们能够将函数标记为“纯粹”或“无副作用”。