I'm trying to understand function declaration using typedefs.
What does this code do in C++?
typedef void fcn_t(void);
typedef void (*ptr_t)(void);
fcn_t f;
fcn_t *pf;
ptr_t pf2;
In my understanding:
fcn_t is the type of a function, and so the line with f is a function declaration (not a definition), and I could later define it like void f(void) { blabla(); bleble(); } just as if I had declared void f(void); instead of fcn_t f;;
fcn_t * is the type of a function pointer, and the line with pf is a pointer variable definition, and pf is default-initialized (assuming the code excerpt is from the global scope);
There is no difference between fcn_t* and ptr_t, thus everything I said about pf applies to pf2.
Did I get it right? Would any of the three declarations have its meaning changed if I marked them extern? What would change if the code was compiled as C instead of as C++?
Yes you are right on all three counts. The only thing that would change if you marked them extern are the function pointers. Function declarations are by default extern in C++.
Try and compile the following program
template <typename...>
struct WhichType;
typedef void fcn_t(void);
typedef void (*ptr_t)(void);
// constexpr auto one = WhichType<fcn_t>{};
// constexpr auto two = WhichType<fcn_t*>{};
// constexpr auto three = WhichType<ptr_t>{};
fcn_t f;
void f() {}
int main() {
f();
}
Uncommenting the commented lines will likely give you a compiler error that tells you what types the WhichType instance is being instantiated with, and as a result it should show you the exact types of all three things you asked about. It's a trick I picked up from Scott Meyers' book "Effective Modern C++".
To test whether the declarations are extern or not, write two simple implementation files, with one containing the definition of the variable
main.cpp
template <typename...>
struct WhichType;
typedef void fcn_t(void);
typedef void (*ptr_t)(void);
fcn_t f;
int main() {
f();
}
definition.cpp
void f() {}
and then compile, link and run definition.cpp and main.cpp (via g++ -std=c++14 definition.cpp main.cpp and then ./a.out). If the declaration was not extern then the compile would fail with an undefined symbol error.
Here is a simple illustration of these typedef
#include <stdio.h>
typedef void fcn_t(void);
typedef void (*ptr_t)(void);
fcn_t f;
fcn_t *pf;
ptr_t pf2;
void
f(void)
{
printf("I am void\n");
}
void
vSayHi(void)
{
printf( "Hi\n" );
}
int
main(void)
{
pf2 = vSayHi;
pf2();
pf = vSayHi;
pf();
f();
return 0;
}
OUTPUT:
Hi
Hi
I am void
I have defined some static functions in their own .h and .cpp files, so these may be called from elsewhere without need for instantiation:
functions.h
#pragma once
class functions {
public:
static const int addition(const int&, const int&);
static const int product(const int&, const int&);
};
functions.cpp
#include "functions.h"
const int functions::addition(const int& op1, const int& op2) {
return op1 + op2;
}
const int functions::product(const int& op1, const int& op2) {
return op1 * op2;
}
I have also created a section for program settings where I will define which of the functions to pick:
constants.h
#pragma once
const int modulus = 10;
extern const int(*operation)(const int&, const int&);
constants.cpp
#include "constants.h"
#include "functions.h"
const int(*operation)(const int&, const int&) = &functions::addition;
This code works as expected using the following sample:
main.cpp
#include <iostream>
#include "constants.h"
int main() {
int a = 7, b = 4;
std::cout << operation(a,b) % modulus << std::endl;
}
Problem is, now I would like to parametrize the functions addition and product using a non-type template, such as:
functions.h
#pragma once
class functions {
public:
template<const int&> static const int addition(const int&, const int&);
};
functions.cpp
#include "functions.h"
template<const int& sub> const int functions::addition(const int& op1, const int& op2) {
return op1 + op2 - sub;
}
The later code breaks, no matter how I try to adapt the other files. I have done everything I reasonably (and pointlessly) could imagine.
Any help on how to rewrite the code on constants.* will be very appreciated.
Templates are instantiated at compile time, and for that the definition must be known - you need to have the template definition in the header.
Even if you do that, you don't have an int as the parameter but a const int&.
That means that you need to instantiate it with an lvalue whose identity (i.e. location) can be determined at compile-time.
In turn, that means that the parameter must be a variable with external linkage - not a temporary or a local variable.
In other words:
extern int x;
void foo()
{
addition<1>(2,3); // Not good; not an lvalue
const int y = 1;
addition<y>(2,3); // Not good; no linkage
addition<x>(2,3); // Good
}
You probably want to use template<int sub> instead.
(Another side note: const references to primitive types are pointless. All they do is add overhead.)
Template definitions should either be visible to the compiler during instantiation, or explicitly instantiated. Since I highly doubt you can explicitly instantiate all your possible versions of integer template, you have put the defginitons into the header.
Than comes the problem of operations. Since it's a function pointer, it can only point to specific instance of your template - the one instantiated with specific integer template. Doubt it's usable at all.
I suggest to rethink your design.
I am trying to access C++ function (f1) and string a from c file using a wrapper function. Code below.
Error thrown is
Error : error: ‘p’ was not declared in this scope
double d = f11( p,i);
1.h
double f11(struct c* p, int i);
1.cpp
#include<iostream>
using namespace std;
class c
{
public: double f1(int i) // how can i access from c
{
cout<<"I am in c++";
}
public : string a; // how can i access string from c
};
extern "C" double f11(c* p, int i) // wrapper function
{
return p->f1(i);
}
2.c
#include<stdio.h>
#include "1.h"
int main()
{
int i=9;
double d = f11( p,i);
}
If you manually include the contents of "1.h" in main.cpp, it would look:
#include <stdio.h>
double f11(struct c* p, int i);
int main()
{
int i=9;
double d = f11( p,i);
}
There are several problems there.
You haven't declared p before using it in the call to f11.
You don't have any way of constructing an object of type struct c in main. Even if you were to fix the compiler errors by providing declarations of struct c and p, you'll run into run time problems since the only way to initialize p will be to initialize it to NULL. That wouldn't do you any good since you have a line
return p->f1(i);
in f11.
Your declaration and definition of f11 will result in linker error. If you want to implement the function as extern "C", you'll also have to declare it as extern "C".
extern "C" double f11(c* p, int i);
In 1.cpp, the member function f1 does not return a double. That is cause for undefined error, if the compiler does not report that as an error.
See working code at http://ideone.com/aVFWFJ. Please note that I changed the implementation of c::f1 so it does not crash.
main.c
#include "stackg.h"
int main()
{
return 0;
}
stackg.h
#ifndef STACKG_H
#define STACKG_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct stack_gt* stack_gt;
stack_gt stkg_init(
void* (*alloc)(const void* data, const int size),
void (*dealloc)(void* data),
void (*copy)(void* data_d, const void* data_s),
const int size
);
void stkg_free(stack_gt s);
int stkg_is_empty(stack_gt s);
int stkg_is_full(stack_gt s);
const int stkg_size(const stack_gt s);
void stkg_clear(stack_gt s);
int stkg_push(stack_gt s, const void* data);
int stkg_pop(stack_gt s, void* data);
int stkg_peek(stack_gt s, void* data);
#ifdef __cplusplus
}
#endif
#endif
The above program compiles successfully with the GCC compiler, but in MSVC2008 it gives the following error :
error C2040: 'stack_gt *' differs in levels of indirection from 'stack_gt'
What should I tell MSVC to make it compile the program without changing anything in the code?
Edit
Error occurs at line 8 of stackg.h :: typedef struct stack_gt* stack_gt;
Edit 2
If nothing else, I'll go with typedef struct _stack_gt* stack_gt;
The problem is that here:
typedef struct stack_gt* stack_gt;
you are giving stack_gt a different type, while this works fine:
typedef struct stack_gt* stack_gtB;
clang gives us a nicer error message:
error: typedef redefinition with different types ('struct stack_gt *' vs 'stack_gt')
This is covered in the draft C++ standard section 7.1.3 The typedef specifier paragraph 6:
In a given scope, a typedef specifier shall not be used to redefine the name of any type declared in that scope to refer to a different type. [ Example:
class complex { / ... / };
typedef int complex; // error: redefinition
—end example ]
Using the same name though is fine, so this would be ok:
typedef struct stack_gt stack_gt;
covered in paragraph 3:
In a given non-class scope, a typedef specifier can be used to redefine the name of any type declared in that scope to refer to the type to which it already refers. [ Example:
typedef struct s { / ... / } s;
typedef int I;
typedef int I;
typedef I I;
—end example ]
Another idea:
#ifdef __cplusplus
extern "C" {
typedef void * stack_gt
#else
typedef struct stack_gt* stack_gt;
#endif
This is ugly, but you don't need to rewrite any other part of the code, only this header included in C++ . It is only used as an opaque pointer in C++ anyways, and C doesn't notice.
I'm developing my code using C++ and want to use MPFIT nonlinear curve fitting library, which is developed in C but allows to compile in C++.
For example I have a class named "myClass", and this class has a function myClass::Execute()
I include "mpfit.h" to myClass.h file. And try to call a function called mpfit from Execute().
int status = mpfit(ErrorFunction, num1, num2, xsub_1D, 0, 0, (void *) &variables, &result);
The problem is ErrorFunction is a function of myClass. So compiler gives error when I try to use this. I tried to carry the ErrorFunction out of the class object, but this time I take the error given below:
Error when the ErrorFunction is outside of the class:
Error 4 error C2664: 'mpfit' : cannot convert parameter 1 from 'int
(__cdecl *)(int,int,double *,double,double *,void *)' to
'mp_func'
Error when the ErrorFunction is inside the class:
Error 3 error C3867: 'myClass::ErrorFunction': function call missing argument list; use '&myClass::ErrorFunction' to
Definition of error function:
int ErrorFunction(int dummy1, int dummy2, double* xsub, double *diff, double **dvec, void *vars)
How can I call this function and parse it into mpfit, which is a C function?
mp_func is defined as:
/* Enforce type of fitting function */
typedef int (*mp_func)(int m, /* Number of functions (elts of fvec) */
int n, /* Number of variables (elts of x) */
double *x, /* I - Parameters */
double *fvec, /* O - function values */
double **dvec, /* O - function derivatives (optional)*/
void *private_data); /* I/O - function private data*/
Make sure that your calling conventions match. C libraries use the C calling convention, or cdecl (__cdecl). If you're using the mp_func typedef within C++, it could be defaulting to the compiler's standard calling convention, or stdcall (__stdcall). Either make a new typedef or change it to the following:
typedef int __cdecl (*mp_func)(int m, /* Number of functions (elts of fvec) */
int n, /* Number of variables (elts of x) */
double *x, /* I - Parameters */
double *fvec, /* O - function values */
double **dvec, /* O - function derivatives (optional)*/
void *private_data); /* I/O - function private data*/
And when you declare ErrorFunction, also declare it as __cdecl:
int __cdecl ErrorFunction(int, int, double*, double *, double **, void *);
If the compiler still complains when calling the mpfit function, you can try casting your function pointer to the mp_func typedef with cdecl:
int status = mpfit((mp_func)ErrorFunction, num1, num2, xsub_1D, 0, 0, (void *) &variables, &result);
Given the definitions of mpfit() and mp_func that you have shown, you would need to use the private_data parameter of mp_func to pass your class's this pointer around. You are currently using that parameter to pass your variables item around instead. Make variables be a member of your class (if it is not already) and then pass this to mpfit() instead:
class MyClass
{
private:
TheDataType variables;
static int ErrorFunction(int m, int n, double *x, double *fvec, double **dvec, MyClass *pThis);
public:
void DoIt();
};
void MyClass::DoIt()
{
// ...
int status = mpfit((mp_func)&ErrorFunction, num1, num2, xsub_1D, 0, 0, this, &result);
// ...
}
int MyClass::ErrorFunction(int m, int n, double* x, double *fvec, double **dvec, MyClass *pThis)
{
// use pThis->variables as needed ...
}
Or:
class MyClass
{
private:
static int MPFitErrorFunction(int m, int n, double *x, double *fvec, double **dvec, MyClass *pThis);
int MyErrorFunction(int m, int n, double *x, double *fvec, double **dvec);
public:
void DoIt();
};
void MyClass::DoIt()
{
// ...
int status = mpfit((mp_func)&MPFitErrorFunction, num1, num2, xsub_1D, 0, 0, this, &result);
// ...
}
int MyClass::MPFitErrorFunction(int m, int n, double* x, double *fvec, double **dvec, MyClass *pThis)
{
return pThis->MyErrorFunction(m, n, x, fvec, dvec);
}
int MyClass::MyErrorFunction(int m, int n, double* x, double *fvec, double **dvec)
{
// use this->variables as needed ...
}
Looks like instead of:
int ErrorFunction(int dummy1, int dummy2, double* xsub, double diff, double *dvec, void *vars)
it should be:
int ErrorFunction(int dummy1, int dummy2, double* xsub, double *diff, double **dvec, void *vars)
to match your
typedef int (*mp_func)(int m, /* Number of functions (elts of fvec) */
int n, /* Number of variables (elts of x) */
double *x, /* I - Parameters */
double *fvec, /* O - function values */
double **dvec, /* O - function derivatives (optional)*/
void *private_data); /* I/O - function private data*/
Your callback must be declared extern "C" for this to work.
Edit: I see people are having hard time grasping this fact. The standard says (7.5/1):
Two function types with different language linkages are distinct types
even if they are otherwise identical.
There's a standard idiom for C++ - to - C, using the pimpl idiom:
foo_c.h:
#ifdef __cplusplus
extern "C" {
#endif
//forward declaration. clients of foo_c.h should only hold pointers to Foo_c
typedef struct Foo_c Foo_c;
int someMethod(Foo_c* foo);
#ifdef __cplusplus
}
#endif
foo_c.cpp:
#include <foo.h>
struct Foo_c {
Foo foo;
}
int someMethod(Foo_c* foo) {
try {
foo->foo.someMethod();
return 0; //no error
}
catch(...) {
return 1; //error
}
}
(Edited for extern "C"'s per below answer.)