Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/155.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++;C库的包装器 最近我发现了一个C库,我想在C++项目中使用它。 此代码配置了全局变量,并将其输出写入静态指针所指向的内存。 当我执行我的项目时,我希望运行两个C程序实例:一个配置为A,一个配置为B。我负担不起两次运行我的程序,因此我认为有两个选项: 制作一个C++包装器:这里的问题是包装器类应该包含C库拥有的所有全局/静态变量。由于C库中的函数使用这些变量,因此我必须为这些函数创建非常大的参数列表 复制粘贴C库:在这里,我必须调整C库中每个函数和每个变量的名称_C++_C_Global Variables_Wrapper_Static Variables - Fatal编程技术网

C++;C库的包装器 最近我发现了一个C库,我想在C++项目中使用它。 此代码配置了全局变量,并将其输出写入静态指针所指向的内存。 当我执行我的项目时,我希望运行两个C程序实例:一个配置为A,一个配置为B。我负担不起两次运行我的程序,因此我认为有两个选项: 制作一个C++包装器:这里的问题是包装器类应该包含C库拥有的所有全局/静态变量。由于C库中的函数使用这些变量,因此我必须为这些函数创建非常大的参数列表 复制粘贴C库:在这里,我必须调整C库中每个函数和每个变量的名称

C++;C库的包装器 最近我发现了一个C库,我想在C++项目中使用它。 此代码配置了全局变量,并将其输出写入静态指针所指向的内存。 当我执行我的项目时,我希望运行两个C程序实例:一个配置为A,一个配置为B。我负担不起两次运行我的程序,因此我认为有两个选项: 制作一个C++包装器:这里的问题是包装器类应该包含C库拥有的所有全局/静态变量。由于C库中的函数使用这些变量,因此我必须为这些函数创建非常大的参数列表 复制粘贴C库:在这里,我必须调整C库中每个函数和每个变量的名称,c++,c,global-variables,wrapper,static-variables,C++,C,Global Variables,Wrapper,Static Variables,哪一个是最快的解决方案? 是否有其他可能运行相同C源的2个实例 谢谢 Max如果您负担不起运行两次,那么运行三次怎么样?可以想象,您可以编写一个小型前端进程来启动C程序的两个独立实例。从使用角度来看,它看起来仍然像一个只运行一次的.exe,但在幕后,您会有一个包含两个子进程的父进程。我不知道这种方法是否适合您的实际需要,但它几乎肯定比您的其他两种方法都快。IIUC,基本上,您拥有的是: extern int a; extern int b; void f(); void g(); 其中a和

哪一个是最快的解决方案? 是否有其他可能运行相同C源的2个实例

谢谢


Max

如果您负担不起运行两次,那么运行三次怎么样?可以想象,您可以编写一个小型前端进程来启动C程序的两个独立实例。从使用角度来看,它看起来仍然像一个只运行一次的.exe,但在幕后,您会有一个包含两个子进程的父进程。我不知道这种方法是否适合您的实际需要,但它几乎肯定比您的其他两种方法都快。

IIUC,基本上,您拥有的是:

extern int a;
extern int b;

void f();
void g(); 
其中
a
b
修改
f()
g()
的行为。对吗

如果你有这个,你想用C++来包装这个,那么你可以做的是:

class the_library {
public:
  the_library(int a, int b) : a_(a), b_(b) {}

  void f() {a=a_; b=b_; ::f();}
  void g() {a=a_; b=b_; ::g();}
private:
  int a_;
  int b_;
})

根据您所拥有的而不是
a
b
,这可能不是非常有效


当然,正如Raki在评论中所说的,因为这是使用全局变量,所以它根本不是线程安全的

我喜欢这里的想法。但是我应该为我需要修改的每个变量创建一个指针。 下面是一个例子:

lib.h:

void f();
int g();
lib.c:

#include "lib.h"
extern int a;
extern int * output;

void f(){
    *output=(*output+6)*a;
}
int g(){
    return *output;
}
object.cc:

#include "lib.h"
#include <iostream>
using namespace std;

int a;
int * output;

class the_library {
public:
  the_library(int a, int * output) : a_(a), output_(output) {}

  void f() {a=a_; output=output_; ::f();}
  int g() {a=a_; output=output_; ::g();}
private:
  int a_;
  int * output_;

};

int main(){

    int out1=2;
    the_library icache(3,&out1);
    icache.f();
    cout<<"icache.f() -> icache is "<<icache.g()<<endl;
    icache.f();
    cout<<"icache.f() -> icache is "<<icache.g()<<endl;

    int out2;
    out2=8;
    the_library dcache(7,&out2);
    dcache.f();
    cout<<"dcache.f()\t-> icache is "<<icache.g()<<endl;
    cout<<"\t\t-> dcache is "<<dcache.g()<<endl;
    return 0;
}
#包括“lib.h”
#包括
使用名称空间std;
INTA;
int*输出;
给图书馆上课{
公众:
_库(inta,int*output):a(a),output(output){
void f(){a=a;output=output;::f();}
int g(){a=a;output=output;::g();}
私人:
INTA_;
int*输出;
};
int main(){
int out1=2;
图书馆icache(3和1);
icache.f();

也许有什么东西让我难以捉摸,但是

…全局变量在线程之间共享,而不是在进程之间共享。。。 这意味着在您的例子中,可以让同一个C程序的两个进程工作,并且它们不会相互干扰,除非它们以某种方式使用进程共享内存

…如果需要在同一进程中运行两个C代码实例。。。 那你就完蛋了

也许是TLS?

您可以将它们分别以线程的形式声明,并将全局变量声明为线程本地存储变量。例如,在VisualC++中,以下代码:

int myGlobalVariable = 42 ;                 // Global variable
__declspec(thread) int myTLSVariable = 42 ; // Thread local variable
每个线程都有自己的变量版本。这样,在线程结束时,您可以将内容复制到其他地方

重写代码。。。 你不需要在其中添加一个C++层。你可以保留C代码,并在结构中声明所有的全局变量:

/* C global variable */
int iMyGlobalVariable = 42 ;
const char * strMyGlobalString = NULL ;
short iMyShortData = 7 ;

/* C struct */
typedef struct MyStruct
{
   int iMyGlobalVariable ;
   const char * strMyGlobalString ;
   short iMyShortData ;
}
MyStruct ;
然后修改函数的原型以接受指向此结构的指针作为第一个参数,然后修改结构成员而不是修改全局变量:

/* old function */
int foo(char *p)
{
   /* fudge with the global variables */
   iMyShortData = 55 ;

   /* etc. */
   fooAgain("Hello World", 42) ;
}
成为:

/* new function */
int foo(MyStruct * s, char *p)
{
   /* fudge with the struct variables */
   s->iMyShortData = 55 ;

   /* etc. */
   fooAgain(s, "Hello World", 42) ;
}
然后,在main中,不是调用第一个函数,而是通过给它一个指向正确结构的指针来调用它。而不是:

int main(int argc, char * argv[])
{
   bar(42, 55) ;
}
你写道:

int main(int argc, char * argv[])
{
   MyStruct A = { /* initialize A's members if needed */ }  ;
   MyStruct B = { /* initialize B's members if needed */ }  ;

   bar(&A, 42, 55) ;
   bar(&B, 42, 55) ;

   return 0 ;
}
在上面的示例中,这两个线程被依次调用,但是您可以启动线程

拯救全球国家? 如果您的代码是单线程的,则可以通过保存/重置全局状态来交错第一个实例的调用和第二个实例的调用

/* C global variable */
int iMyGlobalVariable = 42 ;
short iMyShortData = 7 ;

void saveState(MyStruct * s)
{
   s->iMyGlobalVariable = iMyGlobalVariable ;
   s->iMyShortData = iMyShortData ;
}

void resetState(const MyStruct * s)
{
   iMyGlobalVariable = s->iMyGlobalVariable ;
   iMyShortData = s->iMyShortData ;
}
然后,在需要时调用保存和重置功能:

int main(int argc, char * argv[])
{
   MyStruct A = { /* initialize A's members if needed */ }  ;
   MyStruct B = { /* initialize B's members if needed */ }  ;

   resetState(&A) ; /* now, we work on A */
   bar(42, 55) ;
   saveState(&A) ;  /* we save the progress on A */

   resetState(&B) ; /* now, we work on B */
   bar(42, 55) ;
   saveState(&B) ;  /* we save the progress on B */

   resetState(&A) ; /* now, we work on A */
   foo("Hello World", 3.14159) ;
   saveState(&A) ;  /* we save the progress on A */

   resetState(&B) ; /* now, we work on B */
   foo("Hello World", 3.14159) ;
   saveState(&B) ;  /* we save the progress on B */

   /* etc. */
   return 0 ;
}

这可以用C++代码包起来,自动包装ReStEtS/SaveStand函数。例如:

struct MyWrapper
{
    void foo(const char * p, double d)
    {
       resetState(&m_s) ;
       foo(p, d) ;
       saveState(&m_s) ;
    }

    void bar(int i, short i2)
    {
       resetState(&m_s) ;
       bar(i, i2) ;
       saveState(&m_s) ;
    }

    MyStruct m_s ;
} ;
使您能够将main重新写入为:

int main(int argc, char * argv[])
{
   MyWrapper A ;
   MyWrapper B ;

   A.bar(42, 55) ;
   B.bar(42, 55) ;

   A.foo("Hello World", 3.14159) ;
   B.foo("Hello World", 3.14159) ;

   // etc.

   return 0 ;
}
看起来比C版本好很多。不过,MyWrapper不是线程安全的

结论 第一个解决方案(TLS)是快速的“脏”解决方案,而第二个解决方案是重构代码以正确地编写它(有很好的理由反对全局变量,显然,您偶然发现了其中一个),第三个解决方案是“黑客”使您能够交错两个调用


在所有三种解决方案中,只有第二种方法使得在需要时,将代码包在健壮的线程安全C++类中很容易。

< P>强> C++ +包装> <强> BR> 通过将“整个库”——只是稍微修改一下——粘贴到一个类中,您可以更轻松地完成任务

// C
static char resultBuffer[42];
void ToResult(int x) { ... }
char const * GetResult() { return resultBuffer; }
变成

// C++
class CMyImportantCLib
{
  private:
    char resultBuffer[42];
    void ToResult(int x) { ... } // likely, no code changes at all
    char const * GetResult() { return resultBuffer; }
} ;
主要是声明性的更改(例如“杀死”静态和外部声明)。不过,您需要在方法中查找静态变量,并将它们转换为成员

单独的名称空间
这是一个丑陋的解决方案,但对你来说可能已经足够了:

// impMyLib.h
namespace A 
{
  #include "c-lib.h"
}
namespace B
{
  #include "c-lib.h"
}

// impMyLib.cpp
namespace A 
{
  #include "c-lib.c"
}
namespace B
{
  #include "c-lib.c"
}

如果幸运的话,优化器/链接器成功地折叠了相同的代码。但是,
A:
B:
中的类型是不相关的。

可能值得一提的是,这种方法仅对单线程应用程序是安全的。@Rakis:由于库是使用globals配置的,我认为这一点不必提及评论是针对C++新手,它可能会在将来出现这个线程。我可以看到这个主题很容易被搜索引擎发现。“不言而喻”是相对于你的经验水平。记得大学时你的大学物理教授放弃了那个评论吗?是的。@ R。