Tuesday, June 2, 2015

Digest for comp.lang.c++@googlegroups.com - 23 updates in 3 topics

asetofsymbols@gmail.com: Jun 02 01:36AM -0700

/*
In one asm file compile for result .obj code
section _DATA use32 public class=DATA
 
global u32omul
global u32oadd
global u32osub
global i32omul
global i32oadd
global i32osub
 
section _BSS use32 public class=BSS
section _TEXT use32 public class=CODE
 
;u32 __stdcall u32omul(u32 a, u32 b)
; 0ra, 4P_a, 8P_b
align 4
u32omul:
mov eax, dword[esp+ 4]
cmp eax, -1
je .1
mov edx, dword[esp+ 8]
cmp edx, -1
je .0
mul edx
cmp edx, 0
je .1
.0: mov eax, -1
.1: ret 8
 
;u32 __stdcall u32oadd(u32 a, u32 b)
align 4
u32oadd:
mov eax, dword[esp+ 4]
mov edx, dword[esp+ 8]
add eax, edx
jnc .0
mov eax, -1
.0: ret 8
 
;u32 __stdcall u32osub(u32 a, u32 b)
align 4
u32osub:
mov eax, dword[esp+ 4]
cmp eax, -1
je .1
mov edx, dword[esp+ 8]
cmp edx, -1
je .0
sub eax, edx
jae .1
.0: mov eax, -1
.1: ret 8
 
;i32 __stdcall i32omul(i32 a, i32 b)
align 4
i32omul:
mov eax, dword[esp+ 4]
cmp eax, 0x80000000
je .1
mov edx, dword[esp+ 8]
cmp edx, 0x80000000
je .0
imul edx
jno .1
.0: mov eax, 0x80000000
.1: ret 8
 
 
;i32 __stdcall i32oadd(i32 a, i32 b)
align 4
i32oadd:
mov eax, dword[esp+ 4]
cmp eax, 0x80000000
je .1
mov edx, dword[esp+ 8]
cmp edx, 0x80000000
je .0
add eax, edx
jno .1
.0: mov eax, 0x80000000
.1: ret 8
 
;i32 __stdcall i32osub(i32 a, i32 b)
align 4
i32osub:
mov eax, dword[esp+ 4]
cmp eax, 0x80000000
je .1
mov edx, dword[esp+ 8]
cmp edx, 0x80000000
je .0
sub eax, edx
jno .1
.0: mov eax, 0x80000000
.1: ret 8
 
*/
 
// bcc32 thisfile.cpp asmfile.obj
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <float.h>
#include <limits.h>
#include <iostream.h>
 
#define G(a,b) if(a)goto b
#define R return
#define P printf
#define M malloc
#define Fr free
#define F for
#define S sizeof
#define u8 unsigned char
#define i8 signed char
#define u16 unsigned short
#define i16 signed short
#define u32 unsigned
#define i32 int
#define d64 double
 
// functions for detect u32 or i32 overflow in asm
extern "C" {
u32 __stdcall u32omul(u32 a, u32 b);
u32 __stdcall u32oadd(u32 a, u32 b);
u32 __stdcall u32osub(u32 a, u32 b);
i32 __stdcall i32omul(i32 a, i32 b);
i32 __stdcall i32oadd(i32 a, i32 b);
i32 __stdcall i32osub(i32 a, i32 b);
}
 
// 32 bit unsigned and signed with overflow
class ou32{
public:
 
ou32* val(void){u32 r=ic; ++ic; if(ic>=63) ic=0; R maa+r;}
u32 ErrVal(void){R -1;} // value for error
 
ou32() {v=0;}
ou32(u32 a){v=a; }
ou32(i32 a){v=(u32)(a<0? -1: a);}
ou32(u8 a){v=a;}
ou32(i8 a){v=(u32)(a<0? -1: a);}
ou32(u16 a){v=a;}
ou32(i16 a){v=(u32)(a<0? -1: a);}
 
ou32& operator=(ou32& a){v=a.v; R *this;}
ou32& operator=(u32 a){v=a; R *this;}
ou32& operator=(i32 a){v=(u32)(a<0? -1: a); R *this;}
ou32& operator=(u16 a){v=a; R *this;}
ou32& operator=(i16 a){v=(u32)(a<0? -1: a); R *this;}
ou32& operator=(u8 a){v=a; R *this;}
ou32& operator=(i8 a){v=(u32)(a<0? -1: a); R *this;}
 
ou32& operator*=(ou32& a){v=u32omul(v, a.v); R *this;}
ou32& operator+=(ou32& a){v=u32oadd(v, a.v); R *this;}
ou32& operator-=(ou32& a){v=u32osub(v, a.v); R *this;}
ou32& operator/=(ou32& a){if(v==-1||a.v==-1||a.v==0) v=-1;
else v=v/a.v;
R *this;
}
 
ou32& operator++(){v=(v==-1? -1: ++v); R *this;}
ou32& operator++(int)
{ou32 *t; t=val(); *t=*this; if(v!=-1) ++v; R *t;}
ou32& operator--(){v=(v==-1? -1: --v); R *this;}
ou32& operator--(int)
{ou32 *t; t=val(); *t=*this; if(v!=-1) --v; R *t;}
 
friend ou32& operator*(ou32& a, ou32& b)
{ou32 *r; r=a.val(); r->v=u32omul(a.v, b.v); R *r;}
friend ou32& operator+(ou32& a, ou32& b)
{ou32 *r; r=a.val(); r->v=u32oadd(a.v, b.v); R *r;}
friend ou32& operator-(ou32& a, ou32& b)
{ou32 *r; r=a.val(); r->v=u32osub(a.v, b.v); R *r;}
friend ou32& operator/(ou32& a, ou32& b)
{ou32 *r;
r=a.val();
if(a.v==-1||b.v==-1||b.v==0) r->v=-1;
else r->v=a.v/b.v;
R *r;
}
 
friend ostream& operator<<(ostream& ostr, ou32& a)
{if( a.v==-1 ) ostr<<"ErrElm"; else ostr<<a.v; R ostr;}
 
friend i32 operator==(ou32& a, ou32& b){R a.v==b.v;}
friend i32 operator!=(ou32& a, ou32& b){R a.v==b.v;}
friend i32 operator<=(ou32& a, ou32& b){R a.v<=b.v;}
friend i32 operator>=(ou32& a, ou32& b){R a.v>=b.v;}
friend i32 operator<( ou32& a, ou32& b){R a.v< b.v;}
friend i32 operator>( ou32& a, ou32& b){R a.v> b.v;}
 
friend i32 operator==(ou32& a, u32 b){R a.v==b;}
friend i32 operator!=(ou32& a, u32 b){R a.v==b;}
friend i32 operator<=(ou32& a, u32 b){R a.v<=b;}
friend i32 operator>=(ou32& a, u32 b){R a.v>=b;}
friend i32 operator<( ou32& a, u32 b){R a.v< b;}
friend i32 operator>( ou32& a, u32 b){R a.v> b;}
 
u32 v;
static u32 ic;
static ou32 *maa;
};
 
u32 ou32::ic=0;
ou32 ma[64];
ou32* ou32::maa=ma;
 
void fo(void)
{u32 i, j, k;
ou32 ui, uj, uk;
 
// ou32
ui.v=ui.ErrVal(); // ui.v=-1
--ui.v;
uj=ui+(ou32&)3u; // overflow +
if(uj.v!=-1) P("ou32 error +\n");
 
ui=3u;
uj=ui-(ou32)7u; // overflow -
if(uj.v!=-1) P("ou32 error -\n");
 
 
ui=0xFFFFF;
uj=ui*(u32)0xFFFF; // overflow *
if(uj.v!=-1) P("ou32 error *\n");
 
ui=0xFFFFF;
uj=ui/(u32)0; // overflow /
if(uj.v!=-1) P("ou32 error / \n");
}
 
int main(void)
{if( sizeof(u32)!=4 || sizeof(u16)!=2 )
{P("Basic type error\n"); R 0;}
fo();
 
R 0;
}
/*
Error E2031 over.cpp 219: Cannot cast from 'unsigned int' to 'ou32 &' in function
fo()
Error E2093 over.cpp 223: 'operator-' not implemented in type 'ou32' for arguments
of the same type in function fo()
Error E2094 over.cpp 228: 'operator*' not implemented in type 'ou32' for arguments
of type 'unsigned int' in function fo()
Error E2094 over.cpp 232: 'operator/' not implemented in type 'ou32' for arguments
of type 'unsigned int' in function fo()
Warning W8008 over.cpp 237: Condition is always false in function main()
Warning W8066 over.cpp 238: Unreachable code in function main()
*** 4 errors in Compile ***
 
Why not compile? in the book say that "ou32(u32 a){v=a; }"
does the conversion from unsigned to ou32... or i read wrong?
 
Is it possible define a conversion from unsigned[or type]
to ou32 that use the circular array ma[64]
[possible some cast function]?
 
Thank you
*/
David Brown <david.brown@hesbynett.no>: Jun 02 10:45AM +0200

> [possible some cast function]?
 
> Thank you
> */
 
I /think/ the first error is because you asked to convert the u32 to a
ou32&, while you only have a defined conversion to ou32. It makes no
sense to cast to ou32& in fo().
 
However, if you try writing C++, rather than a mixture of assembly,
toolchain-specific extensions, and complete gibberish, then it would be
a lot easier to help you.
asetofsymbols@gmail.com: Jun 02 03:15AM -0700

Just add some "const" and
All ok this doing what I thought
even if I not find where I
wrote that...
Thank you
 
/*
In one asm file compile for result .obj code
section _DATA use32 public class=DATA
 
global u32omul
global u32oadd
global u32osub
global i32omul
global i32oadd
global i32osub
 
section _BSS use32 public class=BSS
section _TEXT use32 public class=CODE
 
;u32 __stdcall u32omul(u32 a, u32 b)
; 0ra, 4P_a, 8P_b
align 4
u32omul:
mov eax, dword[esp+ 4]
cmp eax, -1
je .1
mov edx, dword[esp+ 8]
cmp edx, -1
je .0
mul edx
cmp edx, 0
je .1
.0: mov eax, -1
.1: ret 8
 
;u32 __stdcall u32oadd(u32 a, u32 b)
align 4
u32oadd:
mov eax, dword[esp+ 4]
mov edx, dword[esp+ 8]
add eax, edx
jnc .0
mov eax, -1
.0: ret 8
 
;u32 __stdcall u32osub(u32 a, u32 b)
align 4
u32osub:
mov eax, dword[esp+ 4]
cmp eax, -1
je .1
mov edx, dword[esp+ 8]
cmp edx, -1
je .0
sub eax, edx
jae .1
.0: mov eax, -1
.1: ret 8
 
;i32 __stdcall i32omul(i32 a, i32 b)
align 4
i32omul:
mov eax, dword[esp+ 4]
cmp eax, 0x80000000
je .1
mov edx, dword[esp+ 8]
cmp edx, 0x80000000
je .0
imul edx
jno .1
.0: mov eax, 0x80000000
.1: ret 8
 
 
;i32 __stdcall i32oadd(i32 a, i32 b)
align 4
i32oadd:
mov eax, dword[esp+ 4]
cmp eax, 0x80000000
je .1
mov edx, dword[esp+ 8]
cmp edx, 0x80000000
je .0
add eax, edx
jno .1
.0: mov eax, 0x80000000
.1: ret 8
 
;i32 __stdcall i32osub(i32 a, i32 b)
align 4
i32osub:
mov eax, dword[esp+ 4]
cmp eax, 0x80000000
je .1
mov edx, dword[esp+ 8]
cmp edx, 0x80000000
je .0
sub eax, edx
jno .1
.0: mov eax, 0x80000000
.1: ret 8
 
*/
 
// bcc32 thisfile.cpp asmfile.obj
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <float.h>
#include <limits.h>
#include <iostream.h>
 
#define G(a,b) if(a)goto b
#define R return
#define P printf
#define M malloc
#define Fr free
#define F for
#define S sizeof
#define u8 unsigned char
#define i8 signed char
#define u16 unsigned short
#define i16 signed short
#define u32 unsigned
#define i32 int
#define d64 double
 
// functions for detect u32 or i32 overflow in asm
extern "C" {
u32 __stdcall u32omul(u32 a, u32 b);
u32 __stdcall u32oadd(u32 a, u32 b);
u32 __stdcall u32osub(u32 a, u32 b);
i32 __stdcall i32omul(i32 a, i32 b);
i32 __stdcall i32oadd(i32 a, i32 b);
i32 __stdcall i32osub(i32 a, i32 b);
}
 
// 32 bit unsigned and signed with overflow
class ou32{
public:
 
friend ou32* val(void)
{u32 r=ic; ++ic; if(ic>=63) ic=0; R maa+r;}
 
friend u32 ErrVal(void){R -1;} // value for error
 
ou32() {v=0;}
ou32(u32 a){v=a;}
ou32(i32 a){v=(u32)(a<0? -1: a);}
ou32(u8 a){v=a;}
ou32(i8 a){v=(u32)(a<0? -1: a);}
ou32(u16 a){v=a;}
ou32(i16 a){v=(u32)(a<0? -1: a);}
ou32(const ou32& a){v=a.v;}
 
ou32& operator=(const ou32& a){v=a.v; R *this;}
ou32& operator=(u32 a){v=a; R *this;}
ou32& operator=(i32 a){v=(u32)(a<0? -1: a); R *this;}
ou32& operator=(u16 a){v=a; R *this;}
ou32& operator=(i16 a){v=(u32)(a<0? -1: a); R *this;}
ou32& operator=(u8 a){v=a; R *this;}
ou32& operator=(i8 a){v=(u32)(a<0? -1: a); R *this;}
 
ou32& operator*=(const ou32& a){v=u32omul(v, a.v); R *this;}
ou32& operator+=(const ou32& a){v=u32oadd(v, a.v); R *this;}
ou32& operator-=(const ou32& a){v=u32osub(v, a.v); R *this;}
ou32& operator/=(const ou32& a){if(v==-1||a.v==-1||a.v==0) v=-1;
else v=v/a.v;
R *this;
}
 
ou32& operator++(){v=(v==-1? -1: ++v); R *this;}
ou32& operator++(int)
{ou32 *t; t=val(); *t=*this; if(v!=-1) ++v; R *t;}
ou32& operator--(){v=(v==-1? -1: --v); R *this;}
ou32& operator--(int)
{ou32 *t; t=val(); *t=*this; if(v!=-1) --v; R *t;}
 
friend ou32& operator*(const ou32& a, const ou32& b)
{ou32 *r; r=val(); r->v=u32omul(a.v, b.v); R *r;}
friend ou32& operator+(const ou32& a, const ou32& b)
{ou32 *r; r=val(); r->v=u32oadd(a.v, b.v); R *r;}
friend ou32& operator-(const ou32& a, const ou32& b)
{ou32 *r; r=val(); r->v=u32osub(a.v, b.v); R *r;}
friend ou32& operator/(const ou32& a, const ou32& b)
{ou32 *r;
r=val();
if(a.v==-1||b.v==-1||b.v==0) r->v=-1;
else r->v=a.v/b.v;
R *r;
}
 
friend ostream& operator<<(ostream& ostr, ou32& a)
{if( a.v==-1 ) ostr<<"ErrElm"; else ostr<<a.v; R ostr;}
 
friend i32 operator==(const ou32& a, const ou32& b){R a.v==b.v;}
friend i32 operator!=(const ou32& a, const ou32& b){R a.v==b.v;}
friend i32 operator<=(const ou32& a, const ou32& b){R a.v<=b.v;}
friend i32 operator>=(const ou32& a, const ou32& b){R a.v>=b.v;}
friend i32 operator<( const ou32& a, const ou32& b){R a.v< b.v;}
friend i32 operator>( const ou32& a, const ou32& b){R a.v> b.v;}
 
u32 v;
static u32 ic;
static ou32 *maa;
};
 
u32 ou32::ic=0;
ou32 ma[64];
ou32* ou32::maa=ma;
 
void fo(void)
{u32 i, j, k;
ou32 ui, uj, uk;
 
// ou32
ui.v=ErrVal(); // ui.v=-1
--ui.v;
uj=ui+3u; // overflow +
if(uj.v!=-1) P("ou32 error +\n");
 
ui=3u;
uj=ui-(ou32)7u; // overflow -
if(uj.v!=-1) P("ou32 error -\n");
 
 
ui=0xFFFFF;
uj=ui*(u32)0xFFFF; // overflow *
if(uj.v!=-1) P("ou32 error *\n");
 
ui=0xFFFFF;
uj=ui/(u32)0; // overflow /
if(uj.v!=-1) P("ou32 error / \n");
 
P("If no print but only this: all ok\n");
 
}
 
int main(void)
{if( sizeof(u32)!=4 || sizeof(u16)!=2 )
{P("Basic type error\n"); R 0;}
fo();
 
R 0;
}
/*
; ui.v=ErrVal(); // ui.v=-1
;
mov dword ptr [ebp-4],-1
;
; --ui.v;
;
dec dword ptr [ebp-4]
;
; uj=ui+3u; // overflow +
;
mov dword ptr [ebp-16],3
mov eax,dword ptr [ebx]
inc dword ptr [ebx]
cmp dword ptr [ebx],63
jb short @2
xor edx,edx
mov dword ptr [ebx],edx
 
#sembra che converte 3u in ou32 utilizzando l'array tramite val()
#inline [**come dovrebbe essere**]
# ma io non ho fatto la conversione u32 a ou32 tramite val()
#tutto automatico?
 
@2:
@3:
mov esi,eax
shl esi,2
add esi,dword ptr [@@ou32@maa]
push dword ptr [ebp-16]
push dword ptr [ebp-4]
call @u32oadd
mov dword ptr [esi],eax
mov eax,esi
mov edx,dword ptr [eax]
mov dword ptr [edi],edx
 
#chiama l'operatore + (ou32 ou32) anche esso inline... ok sembra
;
; if(uj.v!=-1) P("ou32 error +\n");
;
cmp dword ptr [edi],-1
je short @4
push offset s@
call @_printf
pop ecx
;
;
; ui=3u;
;
@4:
mov dword ptr [ebp-4],3
;
; uj=ui-(ou32)7u; // overflow -
;
mov dword ptr [ebp-20],7
mov eax,dword ptr [ebx]
inc dword ptr [ebx]
cmp dword ptr [ebx],63
jb short @5
xor ecx,ecx
mov dword ptr [ebx],ecx
@5:
@6:
mov esi,eax
shl esi,2
add esi,dword ptr [@@ou32@maa]
push dword ptr [ebp-20]
push dword ptr [ebp-4]
call @u32osub
mov dword ptr [esi],eax
mov eax,esi
mov edx,dword ptr [eax]
mov dword ptr [edi],edx
;
; if(uj.v!=-1) P("ou32 error -\n");
;
cmp dword ptr [edi],-1
je short @7
push offset s@+14
call @_printf
pop ecx
;
;
;
; ui=0xFFFFF;
;
@7:
mov dword ptr [ebp-4],1048575
;
; uj=ui*(u32)0xFFFF; // overflow *
;
mov dword ptr [ebp-24],65535
mov eax,dword ptr [ebx]
inc dword ptr [ebx]
cmp dword ptr [ebx],63
jb short @8
xor ecx,ecx
mov dword ptr [ebx],ecx
@8:
@9:
mov esi,eax
shl esi,2
add esi,dword ptr [@@ou32@maa]
push dword ptr [ebp-24]
push dword ptr [ebp-4]
call @u32omul
mov dword ptr [esi],eax
mov eax,esi
mov edx,dword ptr [eax]
mov dword ptr [edi],edx
;
; if(uj.v!=-1) P("ou32 error *\n");
;
cmp dword ptr [edi],-1
je short @10
push offset s@+28
call @_printf
pop ecx
;
;
; ui=0xFFFFF;
;
@10:
mov dword ptr [ebp-4],1048575
;
; uj=ui/(u32)0; // overflow /
;
xor ecx,ecx
mov dword ptr [ebp-28],ecx
mov eax,dword ptr [ebx]
inc dword ptr [ebx]
cmp dword ptr [ebx],63
jb short @11
xor edx,edx
mov dword ptr [ebx],edx
@11:
@12:
mov ecx,eax
shl ecx,2
add ecx,dword ptr [@@ou32@maa]
cmp dword ptr [ebp-4],-1
je short @15
cmp dword ptr [ebp-28],-1
je short @15
cmp dword ptr [ebp-28],0
jne short @13
@15:
mov dword ptr [ecx],-1
jmp short @14
@13:
mov eax,dword ptr [ebp-4]
xor edx,edx
div dword ptr [ebp-28]
mov dword ptr [ecx],eax
@14:
mov eax,ecx
mov ecx,dword ptr [eax]
mov dword ptr [edi],ecx
;
; if(uj.v!=-1) P("ou32 error / \n");
;
?live16387@224: ; EDI = &uj
cmp dword ptr [edi],-1
je short @16
push offset s@+42
call @_printf
pop ecx
;
;
; P("If no print but only this: all ok\n");
;
?live16387@240: ;
@16:
push offset s@+57
call @_printf
pop ecx
;
;
; }
;
*/
red floyd <no.spam@its.invalid>: Jun 02 09:50AM -0700

> [redacted]
 
What part of "x86 Assembly Language isn't C++" are you having trouble
understanding?
"Öö Tiib" <ootiib@hot.ee>: Jun 02 02:26PM -0700

On Tuesday, 2 June 2015 19:50:13 UTC+3, red floyd wrote:
> > [redacted]
 
> What part of "x86 Assembly Language isn't C++" are you having trouble
> understanding?
 
He is perhaps just joking. First asked why we do not discuss
classes for safe and saturated numeric computing and then replies
himself with assembler for processor of past millennia.
asetofsymbols@gmail.com: Jun 02 04:29PM -0700

Red wrote:"
What part of "x86 Assembly Language isn't C++" are you having trouble
understanding?"
 
I not understand const...
For me the type& arguments
in functions are all pointers but
for my definition I
not change them
so they are as const ...
 
If I want change one argument
in a function I would use
funt(T* arg)
not
funt(T& arg)
 
Because in funt(&v)
I can see it changes v when
function is called
 
For the remain C++ offer good
solution to problems
sometime using some
little workaround
in a little subset of C++
 
all I not see or use,
and not want to see
it is too much complex for me
and perhaps for all you too
Lane <software.research.development@gmail.com>: Jun 02 12:03AM -0500

I'm using a C api within the C++ MyClass. This works, but I'd like to be
able to use the private fields (varX) within these callbacks. Is there
anyway to make the callbacks look like class member functions?
 
Currently, things look like the following.
 
// file1.cpp
void read_callback(Dev *dev, const MyData *t)
{
// do stuff ...
}
 
// file2.cpp
class MyClass
{
private:
Dev *dev;
DevListener dl;
 
// how to use these in the callback?
int var1;
long var2;
string var3;
double var4;
 
public:
MyClass();
~MyClass();
 
void operator()() {
 
try {

dl.listener = read_callback;

ret = Dev_addListener(dev, &dl);
// ...
 
ret = Dev_start_async_reads(dev);
// ...
}
catch (const exception& e) {
// exception
}
}
};
"Lőrinczy Zsigmond" <nospam@for.me>: Jun 02 07:22AM +0200

On 2015.06.02. 7:03, Lane wrote:
> I'm using a C api within the C++ MyClass. This works, but I'd like to be
> able to use the private fields (varX) within these callbacks. Is there
> anyway to make the callbacks look like class member functions?
 
If the caller of the callback is passing a 'user-parameter'
to the callback, then a static method might work:
the user-parameter will be the address of the object.
 
Example (with Hungarian comments):
http://web.axelero.hu/lzsiga/cback.cc
Paavo Helde <myfirstname@osa.pri.ee>: Jun 02 12:56AM -0500

Lane <software.research.development@gmail.com> wrote in news:mkjda812947
 
> I'm using a C api within the C++ MyClass. This works, but I'd like to be
> able to use the private fields (varX) within these callbacks. Is there
> anyway to make the callbacks look like class member functions?
 
(1) You can declare callback functions as friends.
 
(2) You can add public member functions to your class which are called by
the callback functions. A bit more tedious, but clearer in the long run.
 
The drawback with (2) is that these member functions are typically not
really "public". A way to cope with that is to add comments like
 
public: // implementation
 
and use some naming schema like Foo_impl() in the method names to indicate
these are not to be called willy-nilly.
 
The static member function approach suggested by another poster is similar
to (1), but a bit unportable (the static member function linkage may or may
not be compatible with the C linkage assumed by the C API). To be fully
portable one needs to use extern "C" callback functions with a C API, and
(static) member functions cannot be declared extern "C".
Cholo Lennon <chololennon@hotmail.com>: Jun 02 09:44AM -0300

On 06/02/2015 02:56 AM, Paavo Helde wrote:
 
> not be compatible with the C linkage assumed by the C API). To be fully
> portable one needs to use extern "C" callback functions with a C API, and
> (static) member functions cannot be declared extern "C".
 
Could you explain a bit more about portability problems? I've always
used static member functions as C library callbacks...
 
TIA
 
 
 
--
Cholo Lennon
Bs.As.
ARG
Martin Shobe <martin.shobe@yahoo.com>: Jun 02 08:57AM -0500

On 6/2/2015 7:44 AM, Cholo Lennon wrote:
>> (static) member functions cannot be declared extern "C".
 
> Could you explain a bit more about portability problems? I've always
> used static member functions as C library callbacks...
 
I don't know of any implementations that do this, but one could have an
implementation that uses one calling convention, say everything on the
stack, for extern "C" functions while the static member functions use a
different one, say the first three in registers with the rest on the
stack. This would cause problems when attempting to call the static
member function from C library. For the example, the first three
arguments would be whatever happened to be in those registers at the
time of the call, the fourth parameter would contain the first
parameter's data[1], etc.
 
Martin Shobe
 
[1] This isn't exactly right. We might have objects of different sizes
that keep them from lining up so nicely. You should still get the idea
of why it's not portable to use static member functions as C library
callbacks.
legalize+jeeves@mail.xmission.com (Richard): Jun 02 05:48PM

[Please do not mail me a copy of your followup]
 
Lane <software.research.development@gmail.com> spake the secret code
 
>I'm using a C api within the C++ MyClass. This works, but I'd like to be
>able to use the private fields (varX) within these callbacks. Is there
>anyway to make the callbacks look like class member functions?
 
C style callback APIs usually have a void* parameter named something
like "user context" that is registered with the callback function.
This opaque pointer value will be passed to the callback function when
it is invoked.
 
The typical adaptation of this to a C++ class is to have the class
delcare a static method and register the static method as the callback
with the 'this' pointer as the context argument. The static method
casts the void* user context pointer back to the appropriate type and
then immediately delegates to an instance method.
 
The static method does not have to be declared extern "C" because
noone is linking to it from a C source file; it is linked within a C++
source file.
 
Example:
 
==== Makefile
callback: callback.o main.o
g++ -o callback $^
 
main.c: callback.h
callback.cpp: callback.h
 
==== callback.h
#if !defined(CALLBACK_H)
#define CALLBACK_H
 
typedef void callback_fn_t(void *context);
 
#if defined(__cplusplus)
extern "C"
{

No comments: