- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我目前正在调试90年代后期编写的一些C++代码,这些代码可以分析脚本以加载数据,执行简单的操作以及打印结果等。
编写代码的人使用函子将要解析的文件中的字符串关键字映射到实际的函数调用,并且将它们进行模板化(最多包含8个参数)以处理用户可能在其请求中请求的各种函数接口(interface)。脚本。
在大多数情况下,这一切都可以正常工作,只是近年来它开始在我们的某些64位构建系统上出现段错误。令我惊讶的是,通过valgrind进行运行时,我发现错误似乎发生在“printf”内部,这是所说的函子之一。以下是一些代码片段,以说明其工作原理。
首先,正在解析的脚本包含以下行:
printf( "%5.7f %5.7f %5.7f %5.7f\n", cos( j / 10 ), tan( j / 10 ), sin( j / 10 ), sqrt( j / 10 ) );
template<class R, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
class FType
{
public :
FType( const void * f ) { _f = (R (*)(T1,T2,T3,T4,T5,T6,T7,T8))f; }
R operator()( T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7,T8 a8 )
{ return _f( a1,a2,a3,a4,a5,a6,a7,a8); }
private :
R (*_f)(T1,T2,T3,T4,T5,T6,T7,T8);
};
template<class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
static Token
evalF(
const void * f,
unsigned int nrargs,
T1 a1,
T2 a2,
T3 a3,
T4 a4,
T5 a5,
T6 a6,
T7 a7,
T8 a8,
vtok & args,
const Token & returnType )
{
Token result;
printf("Count: %i\n",++_count);
if( _count == 2 ) {
const char *fmt = *((const char **) &a1);
result = printf(fmt,a2,a3,a4,a5,a6,a7,a8);
FType<int, const void*,T2,T3,T4,T5,T6,T7,T8> f1(f);
result = f1("Hello, world.\n",a2,a3,a4,a5,a6,a7,a8);
result = f1("Hello, world2 %5.7f\n",a2,a3,a4,a5,a6,a7,a8);
result = f1(fmt,a2,a3,a4,a5,a6,a7,a8);
} else {
FType<int, T1,T2,T3,T4,T5,T6,T7,T8> f1(f);
result = f1(a1,a2,a3,a4,a5,a6,a7,a8);
}
}
==29358== Conditional jump or move depends on uninitialised value(s)
==29358== at 0x92E3683: __printf_fp (printf_fp.c:406)
==29358== by 0x92E05B7: vfprintf (vfprintf.c:1629)
==29358== by 0x92E88D8: printf (printf.c:35)
==29358== by 0x5348C45: FType<int, void const*, double, double, double, double, void const*, void const*, void const*>::operator()(void const*, double, double, double, double, void const*, void const*, void const*) (Interpreter.cc:321)
==29358== by 0x51BAB6D: Token evalF<void const*, double, double, double, double, void const*, void const*, void const*>(void const*, unsigned int, void const*, double, double, double, double, void const*, void const*, void const*, std::vector<Token, std::allocator<Token> >&, Token const&) (Interpreter.cc:542)
#define _VOID_PTR
,它会像原始代码一样使用void *指针来传递函数指针(并触发valgrind错误)。如果注释掉
#define _VOID_PTR
,它将代替WhosCraig建议使用正确原型(prototype)的函数指针。这种情况的问题是,我不能简单地放入
int (*f)(const char *, double, double) = &printf;
,因为编译器抱怨原型(prototype)不匹配(也许我只是很胖,有办法做到这一点?-我猜这是原来的问题作者试图解决void *指针)。为了处理这种特定情况,我使用正确的显式参数列表创建了这个
wrap_printf()
函数。当我执行此版本的代码时,它是valgrind clean。不幸的是,这并没有告诉我们这是void * vs.函数指针存储问题,还是与%al寄存器有关的问题。我认为大多数证据都指向后一种情况,并且我怀疑用固定的参数列表包装
printf()
已迫使编译器执行“正确的事情”:
#include <cstdio>
#define _VOID_PTR // set if using void pointers to pass around function pointers
template<class R, class T1, class T2, class T3>
class FType
{
public :
#ifdef _VOID_PTR
FType( const void * f ) { _f = (R (*)(T1,T2,T3))f; }
#else
typedef R (*FP)(T1,T2,T3);
FType( R (*f)(T1,T2,T3 )) { _f = f; }
#endif
R operator()( T1 a1,T2 a2,T3 a3)
{ return _f( a1,a2,a3); }
private :
R (*_f)(T1,T2,T3);
};
template <class T1, class T2, class T3> int wrap_printf( T1 a1, T2 a2, T3 a3 ) {
const char *fmt = *((const char **) &a1);
return printf(fmt, a2, a3);
}
int main( void ) {
#ifdef _VOID_PTR
void *f = (void *)printf;
#else
// this doesn't work because function pointer arguments don't match printf prototype:
// int (*f)(const char *, double, double) = &printf;
// Use this wrapper instead:
int (*f)(const char *, double, double) = &wrap_printf;
#endif
char a1[]="%5.7f %5.7f\n";
double a2=1.;
double a3=0;
FType<int, const char *, double, double> f1(f);
printf(a1,a2,a3);
f1(a1,a2,a3);
return 0;
}
最佳答案
由64位Linux(和许多其他Unix)使用的System V amd64 ABI,具有固定数量的参数和可变数量的参数的函数在调用方式上有很大不同。
引自“系统V应用程序二进制接口(interface)AMD64架构处理器增补”草案0.99.5 [2],第3.2.3章“参数传递”:
For calls that may call functions that use varargs or stdargs (prototype-less calls or calls to functions containing ellipsis (...) in the declaration) %al is used as hidden argument to specify the number of vector registers used.
关于c++ - 使用模板化仿函数segfaults调用printf(仅64位,在32位中使用valgrind clean),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15341416/
为了让我的代码几乎完全用 Jquery 编写,我想用 Jquery 重写 AJAX 调用。 这是从网页到 Tomcat servlet 的调用。 我目前情况的类似代码: var http = new
我想使用 JNI 从 Java 调用 C 函数。在 C 函数中,我想创建一个 JVM 并调用一些 Java 对象。当我尝试创建 JVM 时,JNI_CreateJavaVM 返回 -1。 所以,我想知
环顾四周,我发现从 HTML 调用 Javascript 函数的最佳方法是将函数本身放在 HTML 中,而不是外部 Javascript 文件。所以我一直在网上四处寻找,找到了一些简短的教程,我可以根
我有这个组件: import {Component} from 'angular2/core'; import {UserServices} from '../services/UserService
我正在尝试用 C 实现一个简单的 OpenSSL 客户端/服务器模型,并且对 BIO_* 调用的使用感到好奇,与原始 SSL_* 调用相比,它允许一些不错的功能。 我对此比较陌生,所以我可能会完全错误
我正在处理有关异步调用的难题: 一个 JQuery 函数在用户点击时执行,然后调用一个 php 文件来检查用户输入是否与数据库中已有的信息重叠。如果是这样,则应提示用户确认是否要继续或取消,如果他单击
我有以下类(class)。 public Task { public static Task getInstance(String taskName) { return new
嘿,我正在构建一个小游戏,我正在通过制作一个数字 vector 来创建关卡,该数字 vector 通过枚举与 1-4 种颜色相关联。问题是循环(在 Simon::loadChallenge 中)我将颜
我有一个java spring boot api(数据接收器),客户端调用它来保存一些数据。一旦我完成了数据的持久化,我想进行另一个 api 调用(应该处理持久化的数据 - 数据聚合器),它应该自行异
首先,这涉及桌面应用程序而不是 ASP .Net 应用程序。 我已经为我的项目添加了一个 Web 引用,并构建了各种数据对象,例如 PayerInfo、Address 和 CreditCard。但问题
我如何告诉 FAKE 编译 .fs文件使用 fsc ? 解释如何传递参数的奖励积分,如 -a和 -target:dll . 编辑:我应该澄清一下,我正在尝试在没有 MSBuild/xbuild/.sl
我使用下划线模板配置了一个简单的主干模型和 View 。两个单独的 API 使用完全相同的配置。 API 1 按预期工作。 要重现该问题,请注释掉 API 1 的 URL,并取消注释 API 2 的
我不确定什么是更好的做法或更现实的做法。我希望从头开始创建目录系统,但不确定最佳方法是什么。 我想我在需要显示信息时使用对象,例如 info.php?id=100。有这样的代码用于显示 Game.cl
from datetime import timedelta class A: def __abs__(self): return -self class B1(A):
我在操作此生命游戏示例代码中的数组时遇到问题。 情况: “生命游戏”是约翰·康威发明的一种细胞自动化技术。它由一个细胞网格组成,这些细胞可以根据数学规则生存/死亡/繁殖。该网格中的活细胞和死细胞通过
如果我像这样调用 read() 来读取文件: unsigned char buf[512]; memset(buf, 0, sizeof(unsigned char) * 512); int fd;
我用 C 编写了一个简单的服务器,并希望调用它的功能与调用其他 C 守护程序的功能相同(例如使用 ./ftpd start 调用它并使用 ./ftpd stop 关闭该实例)。显然我遇到的问题是我不知
在 dos 中,当我粘贴此命令时它会起作用: "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" https://google.
在 dos 中,当我粘贴此命令时它会起作用: "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" https://google.
我希望能够从 cmd 在我的 Windows 10 计算机上调用 python3。 我已重新安装 Python3.7 以确保选择“添加到路径”选项,但仍无法调用 python3 并使 CMD 启动 P
我是一名优秀的程序员,十分优秀!