Zero-size array as struct member

T

thomas

C++ language knows nothing of DLLs. Your first error there is trying
to expose C++ - specific (and not only that, but potentially
particular compiler and standard library version version specific)
interface out of your module.

This is such a massive no-no that it's not even funny. You can only do
that if all modules will be compiled with same compiler (version,
too), and if interface uses standard library, if modules will use same
standard library version and even compilation options. For example,
with STL shipped with VS, compiling a DLL exposing standard containers
in it's interface with/without SECURE_STL breaks low-level binary
compatibility for any container.

It's not a question of liking at all. This sort of interoperability
works only under very specific circumstances (e.g. if you control, or
at least mandate, the build process and the deployment process
__entirely__).

Goran.

I like your words.
In my understanding, your points are:
1. using STL containers in module interface may cause interoperability
problems.
2. my zero-sized array is illegal in C++, so may also cause
interoperability problems.

Both should be avoided.
So the only way is to using pointers or one-sized array.
 
T

thomas

on 20/08/2010 01:06:51 said:
Vladimir Jovic wrote:
thomas wrote:
Hi, I need your help.
----------
struct SvrList{
     unsigned int uNum;
     GameSvr  svr[0];            //line A
};
---------
Once I declared a struct like this to store server list info.
It's supposed to be used like this.
----------
SvrList* pList = (SvrList*)malloc(sizeof(
SvrList) + svrNum*sizeof(GameSvr));
pList->uNum, pList->svr[0], pList->svr[1].... blabla..
I wouldn't call this fine. Even
pList->svr[0]
is accessing the element that is out of array's bounds, and
that is UB.  How come your program is not crashing, or at
least going crazy? Maybe you are just unlucky to have a bug
hidden.
It's an old C programmers hack. I've come across this idiom in
lot's old C code, particularly driver and os code. Microsoft
Win32 is rife with it.
Except that it's not legal C, either.  The C language was
carefully specified so that a bounds checking implementation
would be legal, and the above will fail in such cases.
In C++, of course, the declaration he's looking for is
std::vector<SvrList>, without any manual new.
But I hate vectors. Different distributors may have different
implementations. When I pass vectors between dlls, things unexpected
may happen.

You could define interfaces using "C" linkage and send out vectors as
arrays by simply passing the address of the first element and the size
of the vector, just to make the communication layer happy and compatible.

gotcha!
 
Ö

Öö Tiib

On Aug 20, 2:01 am, Andrey Tarasevich <[email protected]>
wrote:
Pete Becker wrote:
Hi, I need your help.
----------
struct SvrList{
unsigned int uNum;
GameSvr  svr[0];            //line A
};
---------
Once I declared a struct like this to store server list info.
It's supposed to be used like this.
----------
SvrList* pList = (SvrList*)malloc(sizeof(
SvrList) + svrNum*sizeof(GameSvr));
pList->uNum, pList->svr[0], pList->svr[1].... blabla..
I wouldn't call this fine. Even
pList->svr[0]
is accessing the element that is out of array's bounds, and
that is UB.  How come your program is not crashing, or at
least going crazy? Maybe you are just unlucky to have a bug
hidden.
It's an old C programmers hack. I've come across this idiom in
lot's old C code, particularly driver and os code. Microsoft
Win32 is rife with it.
Except that it's not legal C, either.
Which is why it's referred to above as a "hack". Quite a common one, too.
Usually we use the term "hack" when the code relies on a specific
manifestation of undefined (or unspecified) behavior, but otherwise is
well-formed.
In this case the code is ill-formed, since 0-size array declaration is
illegal in C++ (as well as in C). In other words, arguing about the "out
of bounds" access here doesn't make much sense, since the code is
formally non-compilable.
Wait.. I don't think it's illegal in C++. At least I will definitely
object making it illegal by the standard community.
It can be dangerous but it can also do good. It depends on whether we
are using it correctly.
Will you guys getting crazy if we do things like this
-------code-----
struct A{
    int num;
    int p[0];};
A *pA = (A*)malloc(sizeof(A)+sizeof(int)*10);
printf("%d\n", &pA->p[10] - &pA->p[0]);           //accessing out of
bounds.
------code---
Crazy? Why? C++ compilers should not simply compile it by language
rules that does not allow zero-sized arrays. If a compiler compiles it
then it is non-standard extension.
I have seen similar C code, but that used "int p[1];". If it was
compiled with C++ compiler and run-time bounds-checking on then it did
fault when accessing anything but p[0].
In C++ you should use vector<int> instead, it is about as fast.

I hate vectors, again. C++ is not portable as binary code.
Passing vectors as arguments out of a dll in windows may crash the
system when accessing it.

Assuming binary compatibility without effort is wrong anyway. Are you
seriously claiming that such originally-posted hacks let you to
achieve binary compatibility between modules compiled with different C
compilers and under different compilation options?
 
T

thomas

On Aug 20, 2:01 am, Andrey Tarasevich <[email protected]>
wrote:
Pete Becker wrote:
Hi, I need your help.
----------
struct SvrList{
unsigned int uNum;
GameSvr  svr[0];            //line A
};
---------
Once I declared a struct like this to store server list info.
It's supposed to be used like this.
----------
SvrList* pList = (SvrList*)malloc(sizeof(
SvrList) + svrNum*sizeof(GameSvr));
pList->uNum, pList->svr[0], pList->svr[1].... blabla..
I wouldn't call this fine. Even
pList->svr[0]
is accessing the element that is out of array's bounds, and
that is UB.  How come your program is not crashing, or at
least going crazy? Maybe you are just unlucky to have a bug
hidden.
It's an old C programmers hack. I've come across this idiom in
lot's old C code, particularly driver and os code. Microsoft
Win32 is rife with it.
Except that it's not legal C, either.
Which is why it's referred to above as a "hack". Quite a common one, too.
Usually we use the term "hack" when the code relies on a specific
manifestation of undefined (or unspecified) behavior, but otherwise is
well-formed.
In this case the code is ill-formed, since 0-size array declaration is
illegal in C++ (as well as in C). In other words, arguing about the "out
of bounds" access here doesn't make much sense, since the code is
formally non-compilable.
Wait.. I don't think it's illegal in C++. At least I will definitely
object making it illegal by the standard community.
It can be dangerous but it can also do good. It depends on whether we
are using it correctly.
Will you guys getting crazy if we do things like this
-------code-----
struct A{
    int num;
    int p[0];};
A *pA = (A*)malloc(sizeof(A)+sizeof(int)*10);
printf("%d\n", &pA->p[10] - &pA->p[0]);           //accessing out of
bounds.
------code---
Crazy? Why? C++ compilers should not simply compile it by language
rules that does not allow zero-sized arrays. If a compiler compiles it
then it is non-standard extension.
I have seen similar C code, but that used "int p[1];". If it was
compiled with C++ compiler and run-time bounds-checking on then it did
fault when accessing anything but p[0].
In C++ you should use vector<int> instead, it is about as fast.
I hate vectors, again. C++ is not portable as binary code.
Passing vectors as arguments out of a dll in windows may crash the
system when accessing it.

Assuming binary compatibility without effort is wrong anyway. Are you
seriously claiming that such originally-posted hacks let you to
achieve binary compatibility between modules compiled with different C
compilers and under different compilation options?

nope.. I mean using vectors in module interface may cause
interoperability problems.
My hack can solve the problem in case using the same padding policy
for modules involved.
 
Ö

Öö Tiib

On Aug 20, 2:01 am, Andrey Tarasevich <[email protected]>
wrote:
Pete Becker wrote:
Hi, I need your help.
----------
struct SvrList{
unsigned int uNum;
GameSvr  svr[0];            //line A
};
---------
Once I declared a struct like this to store server list info.
It's supposed to be used like this.
----------
SvrList* pList = (SvrList*)malloc(sizeof(
SvrList) + svrNum*sizeof(GameSvr));
pList->uNum, pList->svr[0], pList->svr[1].... blabla..
I wouldn't call this fine. Even
pList->svr[0]
is accessing the element that is out of array's bounds, and
that is UB.  How come your program is not crashing, or at
least going crazy? Maybe you are just unlucky to have a bug
hidden.
It's an old C programmers hack. I've come across this idiom in
lot's old C code, particularly driver and os code. Microsoft
Win32 is rife with it.
Except that it's not legal C, either.
Which is why it's referred to above as a "hack". Quite a common one, too.
Usually we use the term "hack" when the code relies on a specific
manifestation of undefined (or unspecified) behavior, but otherwise is
well-formed.
In this case the code is ill-formed, since 0-size array declaration is
illegal in C++ (as well as in C). In other words, arguing about the "out
of bounds" access here doesn't make much sense, since the code is
formally non-compilable.
Wait.. I don't think it's illegal in C++. At least I will definitely
object making it illegal by the standard community.
It can be dangerous but it can also do good. It depends on whether we
are using it correctly.
Will you guys getting crazy if we do things like this
-------code-----
struct A{
    int num;
    int p[0];};
A *pA = (A*)malloc(sizeof(A)+sizeof(int)*10);
printf("%d\n", &pA->p[10] - &pA->p[0]);           //accessing out of
bounds.
------code---
Crazy? Why? C++ compilers should not simply compile it by language
rules that does not allow zero-sized arrays. If a compiler compiles it
then it is non-standard extension.
I have seen similar C code, but that used "int p[1];". If it was
compiled with C++ compiler and run-time bounds-checking on then it did
fault when accessing anything but p[0].
In C++ you should use vector<int> instead, it is about as fast.
I hate vectors, again. C++ is not portable as binary code.
Passing vectors as arguments out of a dll in windows may crash the
system when accessing it.
Assuming binary compatibility without effort is wrong anyway. Are you
seriously claiming that such originally-posted hacks let you to
achieve binary compatibility between modules compiled with different C
compilers and under different compilation options?

nope.. I mean using vectors in module interface may cause
interoperability problems.
My hack can solve the problem in case using the same padding policy
for modules involved.

If same options and same compiler are used then these interoperability
problems you refer to are likely because you add elements to vector or
attempt to destroy it outside of that windows dll context. Your hack
does not even let to add more elements to it (it is like
vector<GameSvr> const) and you may face same problems with C if you
free() it outside of that dll.
 
A

Alf P. Steinbach /Usenet

* tni, on 20.08.2010 10:52:
None of the C or C++ standards allow an array size of 0.

C99 has flexible arrays (which do basically the same thing), but they
are not included in C++03. Unfortunately, it doesn't look like C99
flexible arrays are part of C++0x either. The somewhat good news is that
GCC, Visual C++ 2010 (and presumably Intel C++) do support them.

It's somewhat bad news.

C99 VLAs are, uh, monstrosities.

I think the reason why C++ did not gain useful variable length array support
(type safe alternative to alloca) was the sheer badness of C99 VLAs...

They don't play well with anything else.


(GCC and Visual C++ support 0-sized arrays as extension.)

Well, at least g++ does. It tricks people.


Cheers,

- Alf
 
T

thomas

On Aug 20, 2:01 am, Andrey Tarasevich <[email protected]>
wrote:
Pete Becker wrote:
Hi, I need your help.
----------
struct SvrList{
unsigned int uNum;
GameSvr  svr[0];            //line A
};
---------
Once I declared a struct like this to store server list info.
It's supposed to be used like this.
----------
SvrList* pList = (SvrList*)malloc(sizeof(
SvrList) + svrNum*sizeof(GameSvr));
pList->uNum, pList->svr[0], pList->svr[1].... blabla..
I wouldn't call this fine. Even
pList->svr[0]
is accessing the element that is out of array's bounds, and
that is UB.  How come your program is not crashing, or at
least going crazy? Maybe you are just unlucky to have a bug
hidden.
It's an old C programmers hack. I've come across this idiom in
lot's old C code, particularly driver and os code. Microsoft
Win32 is rife with it.
Except that it's not legal C, either.
Which is why it's referred to above as a "hack". Quite a common one, too.
Usually we use the term "hack" when the code relies on a specific
manifestation of undefined (or unspecified) behavior, but otherwise is
well-formed.
In this case the code is ill-formed, since 0-size array declaration is
illegal in C++ (as well as in C). In other words, arguing about the "out
of bounds" access here doesn't make much sense, since the code is
formally non-compilable.
Wait.. I don't think it's illegal in C++. At least I will definitely
object making it illegal by the standard community.
It can be dangerous but it can also do good. It depends on whether we
are using it correctly.
Will you guys getting crazy if we do things like this
-------code-----
struct A{
    int num;
    int p[0];};
A *pA = (A*)malloc(sizeof(A)+sizeof(int)*10);
printf("%d\n", &pA->p[10] - &pA->p[0]);           //accessing out of
bounds.
------code---
Crazy? Why? C++ compilers should not simply compile it by language
rules that does not allow zero-sized arrays. If a compiler compiles it
then it is non-standard extension.
I have seen similar C code, but that used "int p[1];". If it was
compiled with C++ compiler and run-time bounds-checking on then it did
fault when accessing anything but p[0].
In C++ you should use vector<int> instead, it is about as fast.
I hate vectors, again. C++ is not portable as binary code.
Passing vectors as arguments out of a dll in windows may crash the
system when accessing it.
Assuming binary compatibility without effort is wrong anyway. Are you
seriously claiming that such originally-posted hacks let you to
achieve binary compatibility between modules compiled with different C
compilers and under different compilation options?
nope.. I mean using vectors in module interface may cause
interoperability problems.
My hack can solve the problem in case using the same padding policy
for modules involved.

If same options and same compiler are used then these interoperability
problems you refer to are likely because you add elements to vector or
attempt to destroy it outside of that windows dll context. Your hack
does not even let to add more elements to it (it is like
vector<GameSvr> const) and you may face same problems with C if you
free() it outside of that dll.

Right, but how about passing out the address of the pointer?
The point is adding more elements may make it necessary to move
existing elements elsewhere, so we may need to modify the pointer in
dll.
Actually passing pointers between functions may also cause this kind
of problems, nothing special to communication between DLLs.
 
J

Juha Nieminen

Öö Tiib said:
In C++ you should use vector<int> instead, it is about as fast.

In which system, exactly?

Unfortunately 'new' (and 'delete') is a rather heavy operation with
most C/C++ standard memory allocators, and if you use std::vector in
the place of the struct hack, you will be doing two 'news' instead of
one malloc().

If that's everything you are doing, then there's no practical difference.
However, if you are instantiating a million objects of the struct type,
then it starts making a big difference.

Additionally, using std::vector there will increase memory fragmentation,
making things even worse.
 
J

Juha Nieminen

Vladimir Jovic said:
What is wrong with next code?


struct SvrList{
unsigned int uNum;
GameSvr *svr;
};

...
SvrList list;
list.uNum = 5;
list.svr = (GameSvr*) malloc( list.uNum * sizeof( GameSvr ) );
...


Since someone pointed out that the original code is used for
performances reasons, how is this worse then the code in the first post?

You have bound 'list' into the scope where it's being instantiated.
When it goes out of scope, the object dies. If that's indeed what you
are trying to do, then there's little difference.

However, if the 'list' object above must survive the scope where it's
created (and possibly shared by several objects), then you will have to
do *two* malloc() calls (or two 'new' calls or whatever). Most malloc/new
implementations in most systems are quite heavy, plus making two allocations
increases memory fragmentation.
 
J

Juha Nieminen

Vladimir Jovic said:
Yes, I must admit I missed that when I posted that code, but later I
realised what was done. The question is still valid : why was it
declared like array of zero size, and not like pointer?

Because if you allocate dynamically an instance of the struct, and the
struct has an array as its last element, you can "overallocate" memory
for the struct and use that extra memory as that array. Thus you need
only one allocation for the dynamically-sized object.

However, if you used a pointer instead of an array, you would need two
allocations: One for the object itself and another for the array. Memory
allocation is unfortunately a relatively heavy operation in most systems.
Moreover, two allocations will increase memory fragmentation more than one.
Your point with operator[] doesn't stand (else thread), as you can use
it for pointers as well.

It was sarcasm. The question was "how can you index a zero-sized array?"
I answered "with operator[]".
 
G

Goran Pusic

I like your words.
In my understanding, your points are:
1. using STL containers in module interface may cause interoperability
problems.
2. my zero-sized array is illegal in C++, so may also cause
interoperability problems.

Both should be avoided.
So the only way is to using pointers or one-sized array.

Well, as far as executable modules interoperability is concerned,
frankly, all bets are off anyhow. Even if you use plain C interface.
You take one compiler/compilation options to build your module, and
another compiler/compilation options to build your caller, and you can
bork it up horribly. E.g. there's nothing to guarantee alignment
issues between compilers/compilation options, nor is there anything to
guarantee that malloc/free between the two are compatible.

Plain C interface is, in theory, just as useless for executable
modules. C language knows nothing of executable modules, so anything
that works, does so through concerted effort off parties involved
(obey alignment rules, use agreed upon alloc/dealloc function, obey
calling conventions etc). There is only this impression that "plain C"
interface "works" and C++ one does not, simply because C++ interface
gets much more complex in no time, and hence there's much more to
break, and faster.

And in reality, it's __all__ about binary interfaces, and neither C
nor C++ make any __provisions__, let alone guarantees. Toolchains do
make provisions, and one (version of a) toolchain gives you a
guarantee, but that's all.

That's why, IMHO, interoperability technologies (e.g. COM) are
paramount. They __mandate__ interoperability (through a spec), that's
their purpose. A toolchain/library-specific implementation of the
interoperability tech has to obey the spec, and only like that can you
inter operate well. When you use e.g. plain C interface, you only get
implicit, kinda-sorta, full of hidden and unspoken presumptions,
interoperability. On the flip side, that mostly works ;-).

Goran.
 
Ö

Öö Tiib

On Aug 20, 2:01 am, Andrey Tarasevich <[email protected]>
wrote:
Pete Becker wrote:
Hi, I need your help.
----------
struct SvrList{
unsigned int uNum;
GameSvr  svr[0];            //line A
};
---------
Once I declared a struct like this to store server list info.
It's supposed to be used like this.
----------
SvrList* pList = (SvrList*)malloc(sizeof(
SvrList) + svrNum*sizeof(GameSvr));
pList->uNum, pList->svr[0], pList->svr[1].... blabla...
I wouldn't call this fine. Even
pList->svr[0]
is accessing the element that is out of array's bounds, and
that is UB.  How come your program is not crashing, or at
least going crazy? Maybe you are just unlucky to have a bug
hidden.
It's an old C programmers hack. I've come across this idiom in
lot's old C code, particularly driver and os code. Microsoft
Win32 is rife with it.
Except that it's not legal C, either.
Which is why it's referred to above as a "hack". Quite a common one, too.
Usually we use the term "hack" when the code relies on a specific
manifestation of undefined (or unspecified) behavior, but otherwise is
well-formed.
In this case the code is ill-formed, since 0-size array declaration is
illegal in C++ (as well as in C). In other words, arguing about the "out
of bounds" access here doesn't make much sense, since the code is
formally non-compilable.
Wait.. I don't think it's illegal in C++. At least I will definitely
object making it illegal by the standard community.
It can be dangerous but it can also do good. It depends on whether we
are using it correctly.
Will you guys getting crazy if we do things like this
-------code-----
struct A{
    int num;
    int p[0];};
A *pA = (A*)malloc(sizeof(A)+sizeof(int)*10);
printf("%d\n", &pA->p[10] - &pA->p[0]);           //accessing out of
bounds.
------code---
Crazy? Why? C++ compilers should not simply compile it by language
rules that does not allow zero-sized arrays. If a compiler compiles it
then it is non-standard extension.
I have seen similar C code, but that used "int p[1];". If it was
compiled with C++ compiler and run-time bounds-checking on then it did
fault when accessing anything but p[0].
In C++ you should use vector<int> instead, it is about as fast.
I hate vectors, again. C++ is not portable as binary code.
Passing vectors as arguments out of a dll in windows may crash the
system when accessing it.
Assuming binary compatibility without effort is wrong anyway. Are you
seriously claiming that such originally-posted hacks let you to
achieve binary compatibility between modules compiled with different C
compilers and under different compilation options?
nope.. I mean using vectors in module interface may cause
interoperability problems.
My hack can solve the problem in case using the same padding policy
for modules involved.
If same options and same compiler are used then these interoperability
problems you refer to are likely because you add elements to vector or
attempt to destroy it outside of that windows dll context. Your hack
does not even let to add more elements to it (it is like
vector<GameSvr> const) and you may face same problems with C if you
free() it outside of that dll.

Right, but how about passing out the address of the pointer?
The point is adding more elements may make it necessary to move
existing elements elsewhere, so we may need to modify the pointer in
dll.
Actually passing pointers between functions may also cause this kind
of problems, nothing special to communication between DLLs.

All problems i have seen people facing there are still about different
c runtimes or memory/resource contexts between DLL and application. So
it is not about passing pointers if you can not free() the thing it
points at since it was malloc()'ed by different memory management.
 
G

Goran Pusic

  In which system, exactly?

  Unfortunately 'new' (and 'delete') is a rather heavy operation with
most C/C++ standard memory allocators, and if you use std::vector in
the place of the struct hack, you will be doing two 'news' instead of
one malloc().

Why? IMO, new and delete are, on the success path, practically
equivalent on many common implementations. Difference is one if on
malloc failure, and new is inlined.

I say this claim of yours is poorly founded.
  Additionally, using std::vector there will increase memory fragmentation,
making things even worse.

In this case, you can use vector::reserve, so not really.

And even locality of reference is not a concern, because allocators
mostly do a good job of allocating blocks close in space if allocation
is close in time. E.g.

std::vector* p = new vector;
p->reserve(X);

is in practice quite OK wrt locality.

I am speaking about locality because on current hardware, and in a
running system, it easily makes more difference than allocation. (I am
speaking abut a case where there's not too create-use-destroy cycles,
of course; and IME(xperience), best course of action when there is a
lot of that, are algorithmic changes; OPs hack comes in dead last,
when other options are explored).

Goran.
 
T

thomas

On Aug 20, 2:01 am, Andrey Tarasevich <[email protected]>
wrote:
Pete Becker wrote:
Hi, I need your help.
----------
struct SvrList{
unsigned int uNum;
GameSvr  svr[0];            //line A
};
---------
Once I declared a struct like this to store server list info.
It's supposed to be used like this.
----------
SvrList* pList = (SvrList*)malloc(sizeof(
SvrList) + svrNum*sizeof(GameSvr));
pList->uNum, pList->svr[0], pList->svr[1].... blabla..
I wouldn't call this fine. Even
pList->svr[0]
is accessing the element that is out of array's bounds, and
that is UB.  How come your program is not crashing, or at
least going crazy? Maybe you are just unlucky to have a bug
hidden.
It's an old C programmers hack. I've come across this idiom in
lot's old C code, particularly driver and os code. Microsoft
Win32 is rife with it.
Except that it's not legal C, either.
Which is why it's referred to above as a "hack". Quite a common one, too.
Usually we use the term "hack" when the code relies on a specific
manifestation of undefined (or unspecified) behavior, but otherwise is
well-formed.
In this case the code is ill-formed, since 0-size array declaration is
illegal in C++ (as well as in C). In other words, arguing about the "out
of bounds" access here doesn't make much sense, since the code is
formally non-compilable.
Wait.. I don't think it's illegal in C++. At least I will definitely
object making it illegal by the standard community.
It can be dangerous but it can also do good. It depends on whether we
are using it correctly.
Will you guys getting crazy if we do things like this
-------code-----
struct A{
    int num;
    int p[0];};
A *pA = (A*)malloc(sizeof(A)+sizeof(int)*10);
printf("%d\n", &pA->p[10] - &pA->p[0]);           //accessing out of
bounds.
------code---
Crazy? Why? C++ compilers should not simply compile it by language
rules that does not allow zero-sized arrays. If a compiler compiles it
then it is non-standard extension.
I have seen similar C code, but that used "int p[1];". If it was
compiled with C++ compiler and run-time bounds-checking on then it did
fault when accessing anything but p[0].
In C++ you should use vector<int> instead, it is about as fast.
I hate vectors, again. C++ is not portable as binary code.
Passing vectors as arguments out of a dll in windows may crash the
system when accessing it.
Assuming binary compatibility without effort is wrong anyway. Are you
seriously claiming that such originally-posted hacks let you to
achieve binary compatibility between modules compiled with different C
compilers and under different compilation options?
nope.. I mean using vectors in module interface may cause
interoperability problems.
My hack can solve the problem in case using the same padding policy
for modules involved.
If same options and same compiler are used then these interoperability
problems you refer to are likely because you add elements to vector or
attempt to destroy it outside of that windows dll context. Your hack
does not even let to add more elements to it (it is like
vector<GameSvr> const) and you may face same problems with C if you
free() it outside of that dll.
Right, but how about passing out the address of the pointer?
The point is adding more elements may make it necessary to move
existing elements elsewhere, so we may need to modify the pointer in
dll.
Actually passing pointers between functions may also cause this kind
of problems, nothing special to communication between DLLs.

All problems i have seen people facing there are still about different
c runtimes or memory/resource contexts between DLL and application. So
it is not about passing pointers if you can not free() the thing it
points at since it was malloc()'ed by different memory management.

Really? DLLs are loaded to the current context and will be in the same
address space. How come the deallocation issue?
 
J

Jorgen Grahn

Vladimir Jovic wrote:
thomas wrote:
Hi, I need your help.
----------
struct SvrList{
    unsigned int uNum;
    GameSvr  svr[0];            //line A
};
---------
Once I declared a struct like this to store server list info.
It's supposed to be used like this.
----------
SvrList* pList = (SvrList*)malloc(sizeof(
SvrList) + svrNum*sizeof(GameSvr));
pList->uNum, pList->svr[0], pList->svr[1].... blabla..
I wouldn't call this fine. Even
pList->svr[0]
is accessing the element that is out of array's bounds, and
that is UB.  How come your program is not crashing, or at
least going crazy? Maybe you are just unlucky to have a bug
hidden.
It's an old C programmers hack. I've come across this idiom in
lot's old C code, particularly driver and os code. Microsoft
Win32 is rife with it.

Except that it's not legal C, either.  The C language was
carefully specified so that a bounds checking implementation
would be legal, and the above will fail in such cases.

In C++, of course, the declaration he's looking for is
std::vector<SvrList>, without any manual new.
But I hate vectors. Different distributors may have different
implementations. When I pass vectors between dlls, things unexpected
may happen.

You may hate vectors, but you should hate the Foo foo[0] hack even more.
Those get hard to manage, and are hard to get rid of once they have
dug into the code base.

You even have to use malloc() in the code above, so your GameSvrs are
poisoned by your choice of container too -- goodbye to things like
constructors and destructors ...

/Jorgen
 
Ö

Öö Tiib

  In which system, exactly?

  Unfortunately 'new' (and 'delete') is a rather heavy operation with
most C/C++ standard memory allocators, and if you use std::vector in
the place of the struct hack, you will be doing two 'news' instead of
one malloc().

  If that's everything you are doing, then there's no practical difference.
However, if you are instantiating a million objects of the struct type,
then it starts making a big difference.

  Additionally, using std::vector there will increase memory fragmentation,
making things even worse.

Ok points taken. If the "about as fast" is not fast enough and you do
not need dynamic array then use boost::array<>, it is vector with
removed overhead of dynamic size. Also it is present in technical
reports IIRC, so eventually comes to C++ as well.
 
A

Alf P. Steinbach /Usenet

* thomas, on 20.08.2010 13:02:
Really? DLLs are loaded to the current context and will be in the same
address space. How come the deallocation issue?

Formally because C++ has no support for dynamic libraries...

In practice, with a Windows DLL, because a DLL can use a different runtime
library implementation (or just instance) than the main program or another DLL
in the same process.


Cheers & hth.,

- Alf
 
Ö

Öö Tiib

On Aug 20, 2:01 am, Andrey Tarasevich <[email protected]>
wrote:
Pete Becker wrote:
Hi, I need your help.
----------
struct SvrList{
unsigned int uNum;
GameSvr  svr[0];            //line A
};
---------
Once I declared a struct like this to store server list info.
It's supposed to be used like this.
----------
SvrList* pList = (SvrList*)malloc(sizeof(
SvrList) + svrNum*sizeof(GameSvr));
pList->uNum, pList->svr[0], pList->svr[1].... blabla..
I wouldn't call this fine. Even
pList->svr[0]
is accessing the element that is out of array's bounds, and
that is UB.  How come your program is not crashing, or at
least going crazy? Maybe you are just unlucky to have a bug
hidden.
It's an old C programmers hack. I've come across this idiom in
lot's old C code, particularly driver and os code. Microsoft
Win32 is rife with it.
Except that it's not legal C, either.
Which is why it's referred to above as a "hack". Quite a common one, too.
Usually we use the term "hack" when the code relies on a specific
manifestation of undefined (or unspecified) behavior, but otherwise is
well-formed.
In this case the code is ill-formed, since 0-size array declaration is
illegal in C++ (as well as in C). In other words, arguing about the "out
of bounds" access here doesn't make much sense, since the code is
formally non-compilable.
Wait.. I don't think it's illegal in C++. At least I will definitely
object making it illegal by the standard community.
It can be dangerous but it can also do good. It depends on whether we
are using it correctly.
Will you guys getting crazy if we do things like this
-------code-----
struct A{
    int num;
    int p[0];};
A *pA = (A*)malloc(sizeof(A)+sizeof(int)*10);
printf("%d\n", &pA->p[10] - &pA->p[0]);           //accessing out of
bounds.
------code---
Crazy? Why? C++ compilers should not simply compile it by language
rules that does not allow zero-sized arrays. If a compiler compiles it
then it is non-standard extension.
I have seen similar C code, but that used "int p[1];". If it was
compiled with C++ compiler and run-time bounds-checking on then it did
fault when accessing anything but p[0].
In C++ you should use vector<int> instead, it is about as fast.
I hate vectors, again. C++ is not portable as binary code.
Passing vectors as arguments out of a dll in windows may crash the
system when accessing it.
Assuming binary compatibility without effort is wrong anyway. Are you
seriously claiming that such originally-posted hacks let you to
achieve binary compatibility between modules compiled with different C
compilers and under different compilation options?
nope.. I mean using vectors in module interface may cause
interoperability problems.
My hack can solve the problem in case using the same padding policy
for modules involved.
If same options and same compiler are used then these interoperability
problems you refer to are likely because you add elements to vector or
attempt to destroy it outside of that windows dll context. Your hack
does not even let to add more elements to it (it is like
vector<GameSvr> const) and you may face same problems with C if you
free() it outside of that dll.
Right, but how about passing out the address of the pointer?
The point is adding more elements may make it necessary to move
existing elements elsewhere, so we may need to modify the pointer in
dll.
Actually passing pointers between functions may also cause this kind
of problems, nothing special to communication between DLLs.
All problems i have seen people facing there are still about different
c runtimes or memory/resource contexts between DLL and application. So
it is not about passing pointers if you can not free() the thing it
points at since it was malloc()'ed by different memory management.

Really? DLLs are loaded to the current context and will be in the same
address space. How come the deallocation issue?

Static variables in DLL are allocated in its own memory context. Such
static variables can be writable. One good way to get rid of writable
static variables in DLLs is to publicly execute the authors and
destroy the carriers of such DLLs or source code. I only am in process
to gain the necessary authority.
 
Ö

Öö Tiib

Static variables in DLL are allocated in its own memory context.

No i was wrong here, sorry. I did look into my papers and it was not
static variable causing it but several c runtimes were linked
statically.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,227
Latest member
Daniella65

Latest Threads

Top