The code below gives the error:
sketch_jul05a:2: error: variable or field 'func' declared void
So my question is: how can I pass a pointer to a struct as a function parameter?
Code:
typedef struct
{ int a,b;
} Struc;
void func(Struc *p) { }
void setup() {
Struc s;
func(&s);
}
void loop()
{
}
The problem is, that the Arduino-IDE auto-translates this into C like this:
#line 1 "sketch_jul05a.ino"
#include "Arduino.h"
void func(Struc *p);
void setup();
void loop();
#line 1
typedef struct
{ int a,b;
} Struc;
void func(Struc *p) { }
void setup() {
Struc s;
func(&s);
}
void loop()
{
}
Which means Struc is used in the declaration of func before Struc is known to the C compiler.
Solution: Move the definition of Struc into another header file and include this.
Main sketch:
#include "datastructures.h"
void func(Struc *p) { }
void setup() {
Struc s;
func(&s);
}
void loop()
{
}
and datastructures.h:
struct Struc
{ int a,b;
};
The answer above works. In the meantime I had found the following also to work, without the need for a .h file:
typedef struct MyStruc
{ int a,b;
} Struc;
void func(struct MyStruc *p) { }
void setup() {
Struc s;
func(&s);
}
void loop()
{
}
Be warned: Arduino coding is a little flaky. Many of the libraries are also a bit flaky!
This next code works for me as in Arduino 1.6.3:
typedef struct S
{
int a;
}S;
void f(S * s, int v);
void f(S * s, int v)
{
s->a = v;
}
void setup() {
}
void loop() {
S anObject;
// I hate global variables
pinMode(13, OUTPUT);
// I hate the "setup()" function
f(&anObject, 0);
// I love ADTs
while (1) // I hate the "loop" mechanism
{
// do something
}
}
Prolly old news, but typedef struct allows member functions (at least in IDE 1.6.4). Depending on what you want to do, of course, but I can't think of any func(struct *p) that couldn't be handled also with object.func(param pdata). Just that something like p->a = 120; becomes something like object.setA(120);
typedef struct {
byte var1;
byte var2;
void setVar1(byte val){
this->var1=val;
}
byte getVar1(void) {
return this->var1;
}
} wtf;
wtf testW = {127,15};
void initwtf(byte setVal) {
testW.setVar1(setVal);
Serial.print("Here is an objective returned value: ");
Serial.println(testW.getVar1());
}
...
void loop() {
initwtf(random(0,100));
}
Related
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define MALLOC(p,s) {\
if (!((p) = malloc(s))) { \
fprintf(stderr, "insufficient memory");\
exit(EXIT_FAILURE);\
}\
}
#define IS_EMPTY(first) (!first)
typedef struct listNode* listPointer;
typedef struct listNode {
int data;
listPointer link;
}listNode;
void printList(listPointer first);
int main(void)
{
int x;
int tmpData;
listPointer first = NULL;
listPointer tmpLink = NULL;
FILE* fp = NULL;
if (!(fp = fopen("in.txt", "r"))) {
fprintf(stderr, "cannot open the file");
exit(EXIT_FAILURE);
}
while (!feof(fp)) {
fscanf(fp, "%d", &tmpData);
MALLOC(tmpLink, sizeof(listNode));
if (IS_EMPTY(first)) {
MALLOC(first, sizeof(listNode));
*tmpLink = *first;
}
tmpLink->data = tmpData;
tmpLink = tmpLink->link;
}
printList(first);
}
void printList(listPointer first)
{
for (; first; first = first->link) {
printf("%d ", first->data);
}
printf("\n");
}
We know that we can implement the insert function.
But I'm really curious about why this doesn't work.
What "first" refers to and what "tmpLink" refers to is the same
After implementing the link list while updating tmpLink,
I'm going to use "first" to print later.
I've spent almost a day just thinking about this, and I've tried debugging it, but I don't know why.
I use an Arduino Uno with Arduino IDE 1.8.3. I have two arrays. I want to write a Deputy function that can add two arrays, and return the result to the main function and print it.
But I want to use x(sizeof(a)), but it seems not correct...
How do I solve this problem?
This is my code:
int a[]={1,2,3,4,5,6},b[]={1,1,1,1,1,1};
void setup() {
Serial.begin(9600);
int *p;
p = add(a,b);
for(int i=0;i<4;i++){
Serial.print(*(p+i));
}
}
void loop() {
}
int * add(int *a,int *b) {
int x = sizeof(a);
int y = sizeof(b);
static int z[4];
for(int i=0;i<4;i++) {
z[i]=a[i]+b[i];
}
return z;
}
int* a does not know the size of the array.
Easiest pass it as an extra parameter.
The next problem is that your static result cannot change its size dynamically.
static has additional problems anyway, in general.
int* add(const int *a,const int *b, int* result, byte size) {
for(byte i=0; i<size; i++) {
result[i]=a[i]+b[i];
}
return result;
}
Returning the result as the return value may be convenient.
In redisAsyncContext, stuct ev was defined:
struct {
void *data;
void (*addRead)(void *privdata);
void (*delRead)(void *privdata);
void (*addWrite)(void *privdata);
void (*delWrite)(void *privdata);
void (*cleanup)(void *privdata);
} ev;
There is a function:
void CleanUpEvent()
{
if (m_pstContext->ev.delRead)
{
m_pstContext->ev.delRead(m_pstContext->ev.data);
}
if (m_pstContext->ev.delWrite)
{
m_pstContext->ev.delWrite(m_pstContext->ev.data);
}
}
How it works? When should I use ev?
Basically you need to provide only connect and disconnect callbacks, rest of things hiredis will do for you alone.
#include <hiredis.h>
#include <async.h>
#include <adapters/libuv.h>
void connectCallback(const redisAsyncContext *c, int status);
void disconnectCallback(const redisAsyncContext *c, int status);
void getCallback(redisAsyncContext *c, void *r, void *privdata);
int main (int argc, char **argv) {
//make a async context
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err) {
/* Let *c leak for now... */
printf("Error: %s\n", c->errstr);
return 1;
}
//now, you need to attach hiredis to your event loop, its depends on event lib that you are using
//example for libuv
redisLibuvAttach(c, uv_default_loop());
//now we setup callbacks
redisAsyncSetConnectCallback(c, connectCallback);
redisAsyncSetDisconnectCallback(c, disconnectCallback);
//enquee "SET foo bar" without callback
redisAsyncCommand(c, NULL, NULL, "SET foo %b", "bar", strlen("bar"));
//enquee "GET foo" with callback and privdata "end-1"
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET foo");
//run your event loop
uv_run(loop, UV_RUN_DEFAULT);
return 0;
}
void connectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Connected...\n");
}
void disconnectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Disconnected...\n");
}
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
if (reply == NULL) return;
printf("argv[%s]: %s\n", (char*)privdata, reply->str);
/* Disconnect after receiving the reply to GET */
redisAsyncDisconnect(c);
}
Check https://github.com/redis/hiredis/tree/master/examples for more examples on different event libraries.
I'm trying to write a dummy network driver and have written the code, but I'm facing issue while trying to load driver i.e. it's crashing the kernel sometimes and sometimes it doesn't respond.
Dummy device code
#include <linux/module.h>
#include <linux/netdevice.h>
int virtualNIC_open(struct net_device *dev) {
printk("virtualNIC_open called\n");
netif_start_queue(dev);
return 0;
}
int virtualNIC_release(struct net_device *dev) {
printk("virtualNIC_release called\n");
netif_stop_queue(dev);
return 0;
}
int virtualNIC_xmit(struct sk_buff *skb, struct net_device *dev) {
printk("dummy xmit function called...\n");
dev_kfree_skb(skb);
return 0;
}
int virtualNIC_init(struct net_device *dev);
const struct net_device_ops my_netdev_ops = {
.ndo_init = virtualNIC_init,
.ndo_open = virtualNIC_open,
.ndo_stop = virtualNIC_release,
.ndo_start_xmit = virtualNIC_xmit,
};
int virtualNIC_init(struct net_device *dev) {
dev->netdev_ops = &my_netdev_ops;
printk("virtualNIC device initialized\n");
}
struct net_device virtualNIC = {
.netdev_ops = &my_netdev_ops,
/* .netdev_ops.ndo_init: virtualNIC_init*/
};
int virtualNIC_init_module(void) {
int result;
strcpy(virtualNIC.name, "virtualNIC");
if((result = register_netdev(&virtualNIC))) {
printk("virtualNIC: Error %d initalizing card ...", result);
return result;
}
return 0;
}
void virtualNIC_cleanup (void)
{
printk ("<0> Cleaning Up the Module\n");
unregister_netdev (&virtualNIC);
return;
}
module_init(virtualNIC_init_module);
module_exit(virtualNIC_cleanup);
MODULE_LICENSE("GPL");
Please help me to figure, where I'm going wrong.
Thanks in Advance
There is already network dummy codec in the mainline kernel. But still if you want to write for the practice. Then I think you can proceed with your own driver as well.
I have modified some of things in your driver. I think you can give one try to it see whether you can see the dummy interface in your ifconfig or not. It is just a sample code (for the interface entry in the ifconfig) and I am not handling any kind of locking or network packet transmission or reception.
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/kernel.h>
#include <linux/etherdevice.h>
struct net_device *virtualNIC;
int virtualNIC_open(struct net_device *dev) {
printk("virtualNIC_open called\n");
return 0;
}
int virtualNIC_release(struct net_device *dev) {
printk("virtualNIC_release called\n");
netif_stop_queue(dev);
return 0;
}
int virtualNIC_xmit(struct sk_buff *skb, struct net_device *dev) {
printk("dummy xmit function called...\n");
dev_kfree_skb(skb);
return 0;
}
const struct net_device_ops my_netdev_ops = {
.ndo_init = virtualNIC_init,
.ndo_open = virtualNIC_open,
.ndo_stop = virtualNIC_release,
.ndo_start_xmit = virtualNIC_xmit,
};
int virtualNIC_init(struct net_device *dev) {
printk("virtualNIC device initialized\n");
return 0;
};
static void virtual_setup(struct net_device *dev){
dev->netdev_ops = &my_netdev_ops;
}
int virtualNIC_init_module(void) {
int result;
virtualNIC = alloc_netdev(0, "virtnC%d", virtual_setup);
if((result = register_netdev(virtualNIC))) {
printk("virtualNIC: Error %d initalizing card ...", result);
return result;
}
return 0;
}
void virtualNIC_cleanup (void)
{
printk ("<0> Cleaning Up the Module\n");
unregister_netdev (virtualNIC);
}
module_init(virtualNIC_init_module);
module_exit(virtualNIC_cleanup);
MODULE_LICENSE("GPL");
This is very helpful, I just want to add this part of code:
virtualNIC = alloc_netdev (0, "virtnC%d", NET_NAME_UNKNOWN, virtual_setup);
this has 4 parameter in new kernel...
I have created a shared memory segment with the help of a binary in C and written some data into it. Now I want read that data from Qt. How to attach to existing shared memory from Qt?
QSharedMemory isn't really meant to interoperate with anything else. On Unix, it is implemented via SYSV shared memory, but it passes Qt-specific arguments to ftok:
::ftok(filename.constData(), qHash(filename, proj_id));
You could emulate this behavior in your C code, but I don't think it's necessary.
Instead of opening a shared memory segment, simply map a file to memory, and access it from multiple processes. On Qt, QFile::map does what you need.
The example below shows both techniques: using SYSV shared memory and using memory-mapped files:
// https://github.com/KubaO/stackoverflown/tree/master/questions/sharedmem-interop-39573295
#include <QtCore>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>
#include <stdexcept>
#include <string>
First, let's have a shared data structure.
struct Data {
int a = 1;
bool b = true;
char c = 'S';
bool operator==(const Data & o) const { return o.a == a && o.b == b && o.c == c; }
static void compare(const void * a, const void * b) {
auto data1 = reinterpret_cast<const Data*>(a);
auto data2 = reinterpret_cast<const Data*>(b);
Q_ASSERT(*data1 == *data2);
}
};
We definitely want error checking, so let's add some helpers that make that easier:
void check(bool ok, const char * msg, const char * detail) {
if (ok) return;
std::string str{msg};
str.append(": ");
str.append(detail);
throw std::runtime_error{str};
}
void check(int f, const char * msg) { check(f != -1, msg, strerror(errno)); }
void check(void * f, const char * msg) { check(f != MAP_FAILED, msg, strerror(errno)); }
void check(bool rc, const QSharedMemory & shm, const char * msg) { check(rc, msg, shm.errorString().toLocal8Bit()); }
void check(bool rc, const QFile & file, const char * msg) { check(rc, msg, file.errorString().toLocal8Bit()); }
And we need RAII wrappers for C APIs:
struct noncopyable { Q_DISABLE_COPY(noncopyable) noncopyable() {} };
struct ShmId : noncopyable {
int id;
ShmId(int id) : id{id} {}
~ShmId() { if (id != -1) shmctl(id, IPC_RMID, NULL); }
};
struct ShmPtr : noncopyable {
void * ptr;
ShmPtr(void * ptr) : ptr{ptr} {}
~ShmPtr() { if (ptr != (void*)-1) shmdt(ptr); }
};
struct Handle : noncopyable {
int fd;
Handle(int fd) : fd{fd} {}
~Handle() { if (fd != -1) close(fd); }
};
Here's how to interoperates SYSV shared memory sections between C and Qt. Unfortunately, unless you reimplement qHash in C, it's not possible:
void ipc_shm_test() {
QTemporaryFile shmFile;
check(shmFile.open(), shmFile, "shmFile.open");
// SYSV SHM
auto nativeKey = QFile::encodeName(shmFile.fileName());
auto key = ftok(nativeKey.constData(), qHash(nativeKey, 'Q'));
check(key, "ftok");
ShmId id{shmget(key, sizeof(Data), IPC_CREAT | 0600)};
check(id.id, "shmget");
ShmPtr ptr1{shmat(id.id, NULL, 0)};
check(ptr1.ptr, "shmat");
new (ptr1.ptr) Data;
// Qt
QSharedMemory shm;
shm.setNativeKey(shmFile.fileName());
check(shm.attach(QSharedMemory::ReadOnly), shm, "shm.attach");
auto ptr2 = shm.constData();
Data::compare(ptr1.ptr, ptr2);
}
Here's how to interoperate memory-mapped files:
void mmap_test() {
QTemporaryFile shmFile;
check(shmFile.open(), "shmFile.open");
shmFile.write({sizeof(Data), 0});
check(true, shmFile, "shmFile.write");
check(shmFile.flush(), shmFile, "shmFile.flush");
// SYSV MMAP
Handle fd{open(QFile::encodeName(shmFile.fileName()), O_RDWR)};
check(fd.fd, "open");
auto ptr1 = mmap(NULL, sizeof(Data), PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd.fd, 0);
check(ptr1, "mmap");
new (ptr1) Data;
// Qt
auto ptr2 = shmFile.map(0, sizeof(Data));
Data::compare(ptr1, ptr2);
}
And finally, the test harness:
int main() {
try {
ipc_shm_test();
mmap_test();
}
catch (const std::runtime_error & e) {
qWarning() << e.what();
return 1;
}
return 0;
}