Objective-C Block Literal Syntax Principle - c++

i'm a iOS programer from china, I'm so sorry that i can't make an exact title for this question, but i'll try to describe it detailed. If there are any one can help me to change the title, i'm very thankful about that. Sorry for my bad English.
When i using clang -rewrite-objc to see the source code about the Block Syntax, i found there is something that i can't understand. Here is my code:
int main(int argc, char *argv[]) {
void (^blk)() = ^ {
};
blk();
}
And the core source code is
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
}
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main(int argc, char *argv[]) {
void (*blk)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);
}
In the main function, when i call the blk(), the source code cast blk and take the FuncPtr by this code
((__block_impl *)blk)->FuncPtr)
I can't really understand that, is it supposed to do? In my opinion, i prefer to use
(((__main_block_impl_0 *)blk ->impl).FuncPtr)
I don't really know more about C++, if there is anyone who can help me to understand the principle of this code, i'll be very thankful. Thanks for you guys.

Well, struct __main_block_impl_0's first member (impl) is a struct __block_impl. So the location of the struct __main_block_impl_0 is the same as the location of the struct __block_impl that is its first member. If you have the pointer to one you can just treat it as a pointer to the other.

Related

I want to push multiple structs in single queue in C++

I have two types of events with associated values such as:
struct EventRequest
{
char EventType;
int RetryCount;
} ER;
struct EventStatus
{
char EventType;
char StatusType;
short RetryCount;
} ES;
I want to push the above structs onto one single queue/stack such as:
queue<typedef>q;
q.push(ER);
q.push(ES);
q.push(ER):
.
.
.
How can I do that?
One solution to this would be polymorphism: both structs inheriting from a common base class. However, that implies an "is-a" relationship that may not exist and would make your code awkward and harder to understand. With that in mind, another solution to this (since C++ 17) would be std::variant.
#include <queue>
#include <variant>
struct EventRequest {
char EventType;
int RetryCount;
} ER;
struct EventStatus {
char EventType;
char StatusType;
short RetryCount;
} ES;
int main() {
std::queue<std::variant<EventRequest, EventStatus>> q;
q.push(ER);
q.push(ES);
return 0;
}
There are several solution to that problem:
Make all strutures to inherit from a same base interface and use smart pointers.
Use unions (old-style)
For this example, I am going to show how to use std::variant
#include <variant>
#include <queue>
struct EventRequest
{
char EventType;
int RetryCount;
};
struct EventStatus
{
char EventType;
char StatusType;
short RetryCount;
};
using AnyEvent = std::variant<EventRequest, EventStatus>;
int main()
{
std::queue<AnyEvent> event;
event.push(EventRequest());
event.push(EventStatus());
return 0;
}
Run this code here:
https://onlinegdb.com/D17aVXA1K

Initializing union in a structure - c++

my code:
#include <iostream>
using namespace std;
struct widget
{
char brand[20];
int type;
union id
{
long id_num;
char id_char[20];
}id_val;
};
int main()
{
widget prize =
{"Rolls", 0, "A2X"};
return 0;
}
The problem is with initialization "A2X" when initializing a union in a structure. Compiler doesn't know I want to choose second option with array of chars when I am passing "A2X", it's requiring long type. When I put
char id_char[20]
before
long id_num
everything is ok. But I want to know how to enforce compiler to accept "A2X" with char as the second option in union. Thank for your help.
But I want to know how to enforce compiler to accept "A2X" with char as the second option in union.
You can use a constructor:
id(char const *id_char) {
std::strcpy(this->id_char, id_char);
}
Alternatively you could use a widget constructor.
A drawback is that the compiler probably won't be able to warn you if you use a too large input string for initialization. The shown trivial constructor can be expanded with strlen to check overflow at runtime. I suggest throwing an exception if you choose to check.
This works with -std=c++11:
#include <cstring>
#include <stdexcept>
struct widget
{
char brand[20];
int type;
union id
{
long id_num;
char id_char[20];
}id_val;
widget(char const*Str, int Type, char const *Id);
};
widget::widget(char const*Str, int Type, char const *Id)
{
if (strlen(Str)+1 > sizeof brand)
throw std::length_error{"brand too large"};
memcpy(brand,Str,strlen(Str)+1);
type = Type;
if (strlen(Id)+1 > sizeof id_val.id_char)
throw std::length_error{"id too large"};
memcpy(id_val.id_char,Id,strlen(Id)+1);
}
int main()
{
widget prize = {"Rolls", 0, "A2X"};
return 0;
}

Why does struct have two variable names in C/C++

In the below code why does the struct have two variable names?
#include <sys/resource.h>
int main (int argc, char **argv)
{
const rlim_t kStackSize = 64L * 1024L * 1024L;
struct rlimit rl; //HERE
int result = getrlimit(RLIMIT_STACK, &rl);
return 0;
}
In C, struct with its tag together is a name, unless it's typedefed.
In C++, you can omit the struct keyword.
If this is C, the struct is just to tell C that it is in a different namespace.
See: understanding C namespaces
If this is C+++, then the struct is not needed.

Expose private internal class size

I need to expose a compile time constant with the size of internal class. To do so I tried next code:
#include <cassert>
struct A
{
//consider Private class as private for this example, just to be able to put the assert like this in main
class Private{};
enum { PrivateSize = sizeof(Private) };
};
int main()
{
//here I have warning on some compilers, signed/unsigned comparison
assert(A::PrivateSize == sizeof(A::Private));
}
My problem is that PrivateSize is signed on some compiler and unsigned on others and I get warnings about this when comparing it with signed types. As far as I know enum's underlying type is implementation defined and can't be forced to be signed or unsigned.
Do you know a way to expose sizeof(A::Private) outside A as compile time constant, but keeping Private class... private? Please note I can't use constexpr as the code will be used on some old compilers.
Following works:
struct A
{
friend int main(int argc, char *argv[]); // For test purpose
private:
class Private{};
public:
static const unsigned int PrivateSize = sizeof (Private);
};
int main(int argc, char *argv[])
{
assert(A::PrivateSize == sizeof(A::Private));
return 0;
}

Access reading error when using class member variable

I have a class with private member variables declared in a header file. In my constructor, I pass in some filenames and create other objects using those names. This works fine. When I try to add another member variable, however, and initialize it in the constructor, I get an access reading violation. I sent the code to someone else and it works fine on his computer. Any idea what could be wrong?
Here is the offending code:
The .h file:
class QUERYMANAGER {
INDEXCACHE *cache;
URLTABLE *table;
SNIPPET *snip;
int* iquery[MAX_QUERY_LENGTH];
int* metapointers[MAX_QUERY_LENGTH];
int blockpointers[MAX_QUERY_LENGTH];
int docpositions[MAX_QUERY_LENGTH];
int numberdocs[MAX_QUERY_LENGTH];
int frequencies[MAX_QUERY_LENGTH];
int docarrays[MAX_QUERY_LENGTH][256];
int qsize;
public:
QUERYMANAGER();
QUERYMANAGER(char *indexfname, char *btfname, char *urltablefname, char *snippetfname, char *snippetbtfname);
~QUERYMANAGER();
This is the .cpp file:
#include "querymanagernew.h"
#include "snippet.h"
using namespace std;
QUERYMANAGER::QUERYMANAGER(char *indexfname, char *btfname, char *urltablefname, char *snippetfname, char *snippetbtfname){
cache = new INDEXCACHE(indexfname, btfname);
table = new URLTABLE(urltablefname);
snip = new SNIPPET(snippetfname, snippetbtfname);
//this is where the error occurs
qsize = 0;
}
I am totally at a loss as to what is causing this - any ideas?
Thanks, bsg
Suggestion, factor out the arrays:
class QUERYMANAGER
{
// Snip
int* iquery[MAX_QUERY_LENGTH];
int* metapointers[MAX_QUERY_LENGTH];
int blockpointers[MAX_QUERY_LENGTH];
int docpositions[MAX_QUERY_LENGTH];
int numberdocs[MAX_QUERY_LENGTH];
int frequencies[MAX_QUERY_LENGTH];
int docarrays[MAX_QUERY_LENGTH][256];
int qsize;
// Snip
};
Looks like you should have another structure:
struct Info
{
int* iquery;
int* metapointers;
int blockpointers;
int docpositions;
int numberdocs;
int frequencies;
int docarrays[256];
};
And the QueryManager now looks like:
class QueryManager
{
INDEXCACHE *cache;
URLTABLE *table;
SNIPPET *snip;
int qsize;
Info details[MAX_QUERY_LENGTH];
};
This may help encapsulate themes a little better.
Your dependencies are probably not right, and the necessary files aren't getting rebuilt. Try a "clean" rebuild.
As a note to style, use initializer lists.
QUERYMANAGER::QUERYMANAGER(char *indexfname, char *btfname, char *urltablefname,
char *snippetfname, char *snippetbtfname) :
cache(new INDEXCACHE(indexfname, btfname)),
table(new URLTABLE(urltablefname)),
snip(new SNIPPET(snippetfname, snippetbtfname)),
qsize(0)
{
}
and you may not need to make those items pointers:
class QUERYMANAGER {
INDEXCACHE cache;
URLTABLE table;
SNIPPET snip;
...
QUERYMANAGER::QUERYMANAGER(char *indexfname, char *btfname, char *urltablefname,
char *snippetfname, char *snippetbtfname) :
cache(indexfname, btfname),
table(urltablefname),
snip(snippetfname, snippetbtfname),
qsize(0)
{
}
Have you built clean? Since accessing the last member variable blows up, but assigning to earlier ones works OK, either you're not constructing/allocating the instance right when you do use it, or you have object files that refer to older versions of the header that didn't have qsize in the object yet, and thus aren't allocating enough space. Or something along those lines.
As expected, this runs just fine on my machine:
#include <cstdlib>
struct INDEXCACHE {};
struct URLTABLE {};
struct SNIPPET {};
const std::size_t MAX_QUERY_LENGTH = 256;
class QUERYMANAGER {
INDEXCACHE *cache;
URLTABLE *table;
SNIPPET *snip;
int* iquery[MAX_QUERY_LENGTH];
int* metapointers[MAX_QUERY_LENGTH];
int blockpointers[MAX_QUERY_LENGTH];
int docpositions[MAX_QUERY_LENGTH];
int numberdocs[MAX_QUERY_LENGTH];
int frequencies[MAX_QUERY_LENGTH];
int docarrays[MAX_QUERY_LENGTH][256];
int qsize;
public:
QUERYMANAGER(char *indexfname, char *btfname, char *urltablefname, char *snippetfname, char *snippetbtfname);
};
QUERYMANAGER::QUERYMANAGER(char *indexfname, char *btfname, char *urltablefname, char *snippetfname, char *snippetbtfname)
: cache(new INDEXCACHE(/*indexfname, btfname*/))
, table(new URLTABLE(/*urltablefname*/))
, snip(new SNIPPET(/*snippetfname, snippetbtfname*/))
, qsize(0)
{
}
int main()
{
QUERYMANAGER foo("blargl", "frxnl", "wrgxl", "brlgl", "srgl");
return 0;
}
So the error must be in the code you're not showing.
BTW, all upper-case names are boo except for macros. They're making your code harder to read and confuse everyone used to a more common coding style.