I'm trying to vulkanize my life. so I can use Vulkan compute. But creating a simple instance fails every way I tried.
Here is the code :
#include <vulkan/vulkan.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char * argv[])
{
VkApplicationInfo vkAppInfo;
vkAppInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
vkAppInfo.apiVersion = VK_API_VERSION_1_0;
VkInstanceCreateInfo vkCreateInfo;
vkCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
vkCreateInfo.pApplicationInfo = &vkAppInfo;
VkInstance instance = VK_NULL_HANDLE;
VkResult result = vkCreateInstance(&vkCreateInfo, NULL, &instance);
return -1;
if (result != VK_SUCCESS) {
return -2;
} else {
return -3;
}
return 0;
}
I tried Vulkan Tutorial (without the graphics function GLFW)
The problem here is that you assume the rest of the fields you do not fill out will be filled out somehow automatically with some valid data, but that is not the case. It will be filled with garbage. Don't forget this is a very general thing in C and C++: Every memory that is not explicitely initialized is just garbage.
I propose you write some wrapper functions for filling your Vulkan structs such as VkApplicationInfo. It could look like this:
VkApplicationInfo fill_app_info(const char* app_name, const char* app_version,
const char* engine_name, uint32_t engine_version,
uint32_t vk_api_version) {
VkApplicationInfo info;
info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
info.pNext = NULL;
info.pApplicationName = app_name;
info.applicationVersion = app_version;
info.pEngineName = engine_name;
info.engineVersion = engine_version;
info.apiVersion = vk_api_version;
return info;
}
This might seem not worth it for VkApplicationInfo, but there are Vulkan structures you will need more often.
Once you wrote the most verbose version of fill_app_info, you can use two powerful tools to make it even more easy for you: default parameters and overloading:
// This is even better: it has default parameters
VkApplicationInfo fill_app_info(const char* app_name, const char* app_version,
const char* engine_name = "MyEngine",
uint32_t engine_version = VK_MAKE_VERSION(1,0,0),
uint32_t vk_api_version = VK_API_VERSION_1_2) {
VkApplicationInfo info;
info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
info.pNext = NULL;
info.pApplicationName = app_name;
info.applicationVersion = app_version;
info.pEngineName = engine_name;
info.engineVersion = engine_version;
info.apiVersion = vk_api_version;
return info;
}
VkApplicationInfo fill_app_info(const char* app_name) {
// Call the other function
return fill_app_info(app_name, VK_MAKE_VERSION(1,0,0));
}
// Call function 1 with all parameters specified
VkApplicationInfo example1 = fill_app_info("MyApp", VK_MAKE_VERSION(1,0,0),
"MyCustomEngine1000", VK_MAKE_VERSION(1,0,6),
VK_API_VERSION_1_1);
// Call function 1 and use default parameters
VkApplicationInfo example2 = fill_app_info("MyApp", VK_MAKE_VERSION(1,0,0));
// Call function 2 and let it fill out everything but the app name
VkApplicationInfo example3 = fill_app_info("MyApp");
As you can see, example3 is created with only one argument specified. This makes your overall code much shorter if you create functions like this for all Vulkan structs. In Vulkan we often have the that we do need to fill out all members of the struct, even if some of the members are not really used. I would also suggest to enable validation layers to check if you use the API ccorrectly. Also, read the Vulkan docs. They tell you how to fill out every struct correctly: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkApplicationInfo.html
Related
When creating a vfs using the tcl api how do you get the current filesystem in Tcl_Filesystem.pathInFilesystemProc
My code looks something like this:
typedef struct {
FILE* dbFile;
/*...*/
} FSBackend;
void createFS(const char* dbFile)
{
FSBackend* fsback = (FSBackend*)malloc(sizeof(FSBackend));
initDb(fsback,dbFile);
Tcl_Filesystem tfs;
tfs.typeName="Db Fs";
tfs.structureLength = sizeof(Tcl_Filesystem);
tfs.version = TCL_FILESYSTEM_VERSION_1;
tfs.pathInFilesystemProc = inFsProc;
/*...*/
Tcl_FSRegister((void*),tfs);
}
int inFsProc(Tcl_Obj* pathPtr,ClientData* cd)
{
/* How do I get my FSBackend struct here */
FSBackend* bk = /* ? */
int len;
const char* searchPath = Tcl_GetStringFromObj(pathPtr,&len);
char* foundPath = findFileInDb(searchPath,bk);
if (foundPath == 0) {
return -1;
}
cd = buildInternalRep(foundPath,bk);
return TCL_OK;
}
/**
...
*/
int main()
{
createFS("db1.db");
createFS("db2.db");
}
How do I, in inFsProc get back the struct I passed into Tcl_FSRegister?
The Tcl_FSData function says it can get it but I would then need to get a Tcl_Filesystem pointer
That's a weird one. The clientData handle there is not used to specify a mount point, but rather a separate capability of the filesystem type. Tcl's internal use of Tcl_FSRegister doesn't use it at all. The code which is as close as anything to a canonical use of it is the tclvfs package.
https://github.com/tcl-mirror/tclvfs/blob/master/generic/vfs.c#L385 shows us the use:
static void
Vfs_RegisterWithInterp(interp)
Tcl_Interp *interp;
{
ClientData vfsAlreadyRegistered;
/*
* We need to know if the interpreter is deleted, so we can
* remove all interp-specific mounts.
*/
Tcl_SetAssocData(interp, "vfs::inUse", (Tcl_InterpDeleteProc*)
Vfs_UnregisterWithInterp, (ClientData) 1);
/*
* Perform one-off registering of our filesystem if that
* has not happened before.
*/
vfsAlreadyRegistered = Tcl_FSData(&vfsFilesystem);
if (vfsAlreadyRegistered == NULL) {
Tcl_FSRegister((ClientData)1, &vfsFilesystem);
Tcl_CreateExitHandler(VfsExitProc, (ClientData)NULL);
Tcl_CreateThreadExitHandler(VfsThreadExitProc, NULL);
}
}
As you can see, the clientData there is really just being used as a marker so the code knows whether to do one-time initialisation.
To discover what the mount mapping is, you'll need to keep internal structures. You're strongly recommended to make the Tcl_Filesystem structure instance itself be global (or rather static at file scope) in your code.
void main(int argc, char* argv[]) {
char* hostname = (char*)malloc(sizeof(char)*1024);
hostname = getClientHostName("122.205.26.34");
printf("%s\n", hostname);
free(hostname);
}
char* getClientHostName(char* client_ip) {
char hostnames[5][2];
hostnames[0][0] = "122.205.26.34";
hostnames[0][1] = "aaaaa";
hostnames[1][0] = "120.205.36.30";
hostnames[1][1] = "bbbbb";
hostnames[2][0] = "120.205.16.36";
hostnames[2][1] = "ccccc";
hostnames[3][0] = "149.205.36.46";
hostnames[3][1] = "dddddd";
hostnames[4][0] = "169.205.36.33";
hostnames[4][1] = "eeeeee";
for(int i = 0; i<5; i++) {
if(!strcmp(hostnames[i][0], client_ip))
return (char*)hostnames[i][1];
}
return NULL;
}
Beginner in C.
I am not sure if there would be a better way to implement what I am trying to implement. The code is self-explanatory. Is there any way that I can predefine the size of hostname, using some general size of IP addresses, to avoid seg fault? Is there a even better way where I don't have to hardcode the size?
After fixing the compiler errors and warnings you get:
const char* getClientHostName(const char* client_ip) {
const char * hostnames[5][2];
hostnames[0][0] = "122.205.26.34";
hostnames[0][1] = "aaaaa";
hostnames[1][0] = "120.205.36.30";
hostnames[1][1] = "bbbbb";
hostnames[2][0] = "120.205.16.36";
hostnames[2][1] = "ccccc";
hostnames[3][0] = "149.205.36.46";
hostnames[3][1] = "dddddd";
hostnames[4][0] = "169.205.36.33";
hostnames[4][1] = "eeeeee";
for(int i = 0; i<5; i++) {
if(!strcmp(hostnames[i][0], client_ip))
return hostnames[i][1];
}
return NULL;
}
int main(int argc, char* argv[]) {
const char * hostname = getClientHostName("128.205.36.34");
printf("%s\n", hostname);
}
Is there a even better way where I don't have to hardcode the size?
Take the habit to compile with all warnings and debug info: gcc -Wall -Wextra -g with GCC. Improve the code to get no warnings at all.
If you want to get genuine IP addresses, this is operating system specific (since standard C11 don't know about IP addresses; check by reading n1570). On Linux you would use name service routines such as getaddrinfo(3) & getnameinfo(3) or the obsolete gethostbyname(3).
If this is just an exercise without actual relationship to TCP/IP sockets (see tcp(7), ip(7), socket(7)) you could store the table in some global array:
struct myipentry_st {
const char* myip_hostname;
const char* myip_address;
};
then define a global array containing them, with the convention of terminating it by some {NULL, NULL} entry:
const struct myipentry_st mytable[] = {
{"aaaaa", "122.205.26.34"},
{"bbbb", "120.205.36.30"},
/// etc
{NULL, NULL} // end marker
};
You'll better have a global or static variable (not an automatic one sitting on the call stack) because you don't want to fill it on every call to your getClientHostName.
Then your lookup routine (inefficient, since in linear time) would be:
const char* getClientHostName(char* client_ip) {
for (const struct myipentry_st* ent = mytable;
ent->myip_hostname != NULL;
ent++)
// the if below is the only statement of the body of `for` loop
if (!strcmp(ent->myip_address, client_ip))
return ent->myip_hostname;
// this happens after the `for` when nothing was found
return NULL;
}
You could even declare that table as a heap allocated pointer:
const struct myipentry_st**mytable;
then use calloc to allocate it and read its data from some text file.
Read the documentation of every standard or external function that you are using. Don't forget to check against failure (e.g. of calloc, like here). Avoid memory leaks by appropriate calls to free. Use the debugger gdb and valgrind. Beware of undefined behavior.
In the real world, you would have perhaps thousands of entries and you would perform the lookup many times (perhaps millions of times, e.g. once per every HTTP request in a web server or client). Then choose a better data structure (hash table or red-black tree perhaps). Read some Introduction to Algorithms.
Add * to type definition char * hostnames[5][2]. This must be array of pointers, not simple chars. Another necessary change is strcpy instead of = in strcpy( hostname, getClientHostName("122.205.26.34") );.
PS: Always try to compile with 0 compiler warnings, not only 0 errors!
I have looked at the examples of passing a struct by both value and reference. My code compiles but is not working as it should. I am using C to program a micro-controller so it is hard to check if it is working properly, but I am not getting the desired output.
So, as per instructions, I first define my structure:
struct package //define a structure type called package.
{
unsigned char
wavType,startFreq1,startFreq2,startFreq3,startFreq4,
stopFreq1,stopFreq2,
stopFreq3,stopFreq4,step,dura,amp,sett; //define bytes to use
};
In the main method I create an instance of it:
struct package p; //create a new instance of Package
Now I pass it by reference (pointer - because I'm using C) to a function:
getPackage(&p);
Within the function getpackage() I update the values of the respective elements of p:
getPackage(struct package *p) //Get data package
{
p->wavType = receive();
p->startFreq1 = receive();
p->startFreq2 = receive();
p->startFreq3 = receive();
p->startFreq4 = receive();
p->stopFreq1 = receive();
p->stopFreq2 = receive();
p->stopFreq3 = receive();
p->stopFreq4 = receive();
p->step = receive();
p->dura = receive();
p->amp = receive();
p->sett = receive();
}
This is the receive function:
unsigned char receive(void)
{
unsigned char dataR = 0x00;
for(signed char i = 0; i <=7 ;i++)
{
dataR |= PORTBbits.RB1 << i; //move the value on the data pin to a bit in dataR
}
return dataR;
}
QUESTION: Will this correctly update the bytes in the package p? Also, does package p need to be returned if I want to use it elsewhere? I ask this because....
I now pass the package p, by value, into another function using:
sendSine(p);
This function makes use of the value of the bytes in the package p:
void sendSine(struct package p)
{
dataL = p.startFreq1;
dataH = p.startFreq2;
send(dataL,dataH);
dataL = p.startFreq3;
dataH = p.startFreq4;
send(dataL,dataH);
}
I know the function send(dataL,dataH) is working because I have tested it by setting dataL and dataH by hand and I get the required result, so there must be an error along the way with the struct - I just cant figure out where... Can anyone help me with were it might be?
The receive function seems to be the procedure in question. Try writing a stub-replacement for receive, such as:
unsigned char receive(void)
{
unsigned char X = 'a';
// or whatever value you want to simulate as being received
return X;
}
and then try running your complete application, tf it works then go back and re-think your original receive per some of the comments that have already been made.
static struct dll_wifi_state **dll_states;
enum dll_type {
DLL_UNSUPPORTED,
DLL_ETHERNET,
DLL_WIFI
};
struct dll_state {
enum dll_type type;
union {
struct dll_eth_state *ethernet;
struct dll_wifi_state *wifi;
} data;
};
static struct dll_state *dll_states = NULL;
struct dll_wifi_state {
int link;
// A pointer to the function that is called to pass data up to the next layer.
up_from_dll_fn_ty nl_callback;
bool is_ds;
};
This is the method whose pointer is being passed in the dll_wifi_state struct.
static void up_from_dll(int link, const char *data, size_t length)
{
//some code here
}
In other file, I am calling this method
void reboot_accesspoint()
{
// We require each node to have a different stream of random numbers.
CNET_srand(nodeinfo.time_of_day.sec + nodeinfo.nodenumber);
// Provide the required event handlers.
CHECK(CNET_set_handler(EV_PHYSICALREADY, physical_ready, 0));
// Prepare to talk via our wireless connection.
CHECK(CNET_set_wlan_model(my_WLAN_model));
// Setup our data link layer instances.
dll_states = calloc(nodeinfo.nlinks + 1, sizeof(struct dll_state));
for (int link = 0; link <= nodeinfo.nlinks; ++link) {
switch (linkinfo[link].linktype) {
case LT_LOOPBACK:
dll_states[link].type = DLL_UNSUPPORTED;
break;
case LT_WAN:
dll_states[link].type = DLL_UNSUPPORTED;
break;
case LT_LAN:
dll_states[link].type = DLL_ETHERNET;
dll_states[link].data.ethernet = dll_eth_new_state(link, up_from_dll);
break;
case LT_WLAN:
dll_states[link].type = DLL_WIFI;
dll_states[link].data.wifi = dll_wifi_new_state(link,
up_from_dll,
true /* is_ds */);
break;
}
}
// printf("reboot_accesspoint() complete.\n");
}
It works fine like this, but I want to add another argument i.e. up_from_dll((int link, const char *data, size_t length, int seq). And as soon as I add this argument, following error starts coming up
ap.c:153: warning: passing argument 2 of ‘dll_wifi_new_state’ from incompatible pointer type
Is there a way of adding another argument to that method without getting error ??? I am really bad with pointers :(
Any help would be much appreciated.
Line 153 :
dll_states[link].data.wifi = dll_wifi_new_state(link,
up_from_dll,
true /* is_ds */);
And method
struct dll_wifi_state *dll_wifi_new_state(int link,
up_from_dll_fn_ty callback,
bool is_ds)
{
// Ensure that the given link exists and is a WLAN link.
if (link > nodeinfo.nlinks || linkinfo[link].linktype != LT_WLAN)
return NULL;
// Allocate memory for the state.
struct dll_wifi_state *state = calloc(1, sizeof(struct dll_wifi_state));
// Check whether or not the allocation was successful.
if (state == NULL)
return NULL;
// Initialize the members of the structure.
state->link = link;
state->nl_callback = callback;
state->is_ds = is_ds;
return state;
}
I haven't changed anything else apart from adding the new parameter to up_from_dll.
The second parameter to dll_wifi_new_state is up_from_dll_fn_ty callback.
It's not in your code listing right now, but up_from_dll_fn_ty is a typedef saying that the up_from_dll_fn_ty is a function pointer with specific parameters (which don't include int seq)
When you updated up_from_dll with different parameters, it no longer matches the type specified by up_from_dll_fn_ty and expected as the second parameter for dll_wifi_new_state. You'll need to add the parameter to up_from_dll_fn_ty and you should be good.
If you post the definition of up_from_dll_fn_ty, it would make the question have all the information and allow me to help you more if you still need it.
You're looking for something like:
typedef void (*up_from_dll_fn_ty)(int link, const char *data, size_t length);
and change it to
typedef void (*up_from_dll_fn_ty)(int link, const char *data, size_t length, int seq);
Here's a link to a question that has good information about creating typedefs for function pointers:
Understanding typedefs for function pointers in C
I have some code in the following kind of layout, I believe that the topExample/botExample aren't being set properly when I call addTopBotExample. I think this is due to the top bot variables being on the functions stack and so being cleared when the function ends? I have a feeling that perhaps I need to malloc the memory first, but am not sure how I would go about doing this are even if its the right approach.
typedef struct Example Example;
struct Example {
/* normal variables ...*/
Example *topExample;
Example *botExample;
};
....
void addTopBotExample(Example **example, int someVariable) {
Example top = createTopExample(int someVariable); //(createTopExample returns a
//type Example based on some input)
Example bot = createBotExample(int someVariable);
(*example)->topExample = ⊤
(*example)->botExample = ⊥
return;
}
If createTopExample isn't allocating memory, this is going to cause problems the moment it's called more than once. Rewrite createTopExample and createBotExample to use malloc and return an Example*. Something like this:
Example* createTopExample(stuff)
{
Example *example = malloc(sizeof(Example));
// ... stuff you do
return example;
}
Then your addTopBotExample would look like this:
void addTopBotExample(Example **example, int someVariable) {
if ((*example)->topExample)
free((*example)->topExample)
if ((*example)->botExample)
free((*example)->botExample)
(*example)->topExample = createTopExample(int someVariable);
(*example)->botExample = createBotExample(int someVariable);
return;
}
Note that this addTopBotExample will free the allocated memory before calling malloc again but before your program ends, you need to call free on any lingering Examples that used this addTopBotExample function:
free(exampleInstanceThatWasPassedIntoAddTopBotExampleAtSomePoint.topExample);
free(exampleInstanceThatWasPassedIntoAddTopBotExampleAtSomePoint.botExample);
You have already everything together. Allocate the Example in createTopExample or createTopExample
Example *createTopExample(int someVariable)
{
Example *x = malloc(sizeof(Example));
/* initialize x */
return x;
}
and in addTopBotExample
void addTopBotExample(Example *example, int someVariable) {
Example *top = createTopExample(int someVariable); //(createTopExample returns a
//type Example based on some input)
Example *bot = createBotExample(int someVariable);
example->topExample = top;
example->botExample = bot;
return;
}
Ooooo, this is bad. The expression "Example top" in the addTopBotExample() function allocated that object on the stack. It'll be trashed after exiting from the function. (Same for "Example bot" on the following line.) Something like this will work better:
void addTopBotExample(Example **example, int someVariable) {
Example *top = createTopExample(someVariable); // NOTE THE *
Example *bot = createBotExample(someVariable); // NOTE THE *
(*example)->topExample = top; // NOT &top !!
(*example)->botExample = bot; // NOT &bot !!
return;
}
And you'll want to write createTopExample and createBotExample so they return pointers:
#include <stdlib.h> // For malloc!
Example *createTopExample(stuff) // Note *. It's returning a pointer.
{
Example *example = malloc(sizeof(Example)); // Allocate on the HEAP. Lives after this function call.
// Fill in the fields of example.
example->field1 = 25; // Note the "->": you're dereferencing a pointer.
example->title = "Example title";
return example;
}