c programming default parameters: const struct vs init function - c

Suppose I have something like:
typedef struct
{
int parameter1;
int parameter2;
void (fp*)(void);
} STATE_T;
and I have various sets of default parameters to start the program(or this segment of the program) in different states.
STATE_T State;
void InitState1()
{
State.parameter1 = 123;
State.parameter2 = 321;
State.fp = Function1;
}
void InitState2()
{
State.parameter1 = 0;
State.parameter2 = 1;
State.fp = Function2;
}
or would it better to use const structs
const STATE_T STATE1 =
{
123,
321,
Function1
}
const STATE_T STATE2 =
{
0,
1,
Function2
}
I suppose in the 2nd case either a pointer can be used or a function to copy a selection of settings:
STATE_T * StatePtr;
StatePtr = &STATE1;
or
void InitState(STATE_T s)
{
State.parameter1 = s.parameter1;
State.parameter2 = s.parameter2;
State.fp = s.fp;
}
After typing out all the examples, it seems like, in the case I want to change all parameters at the same time, using a pointer to const structs would be more efficient, while an init functions would be better for only updating selected parameters that would be relevant. Are there any other advantages or differences to be aware of?

I typically declares some static versions statically ie
static State State1 = {
.paramater1 = 123,
.parameter2 = 321,
.fp = NULL,
};
static State State2 = {
.paramater1 = 999,
.parameter2 = 111,
.fp = NULL,
};
Then in an init function assign the statics to get the defaults...
static State * newState(int state) {
State *foo = calloc(1, sizeof(State));
assert(foo != NULL);
if(state == 1) {
*foo = State1;
foo->fp = function_fp1;
}
else {
*foo = State2;
foo->fp = function_fp2;
}
return foo;
}

Related

How to read structure field values from writecallback in open62541

Currently, I'm working on read and write callback in open62541, I created a structure variable XV type, It's fields are X and V in XML file
X is a type of double and V is a type of float
if I write the value using the client tool it's entering into the write callback function and I'm able to print the X value alone using the print cout<<"Field value is "<< *(double*)data->value.data<<endl;, but I'm unable to fetch the second value that is V,
I took the below code as a reference, in that in the afterWriteTime callback function I tried
cout<<"Field value is "<< *(double*)data->value.data<<endl;this print statemet
it's printing only the X's value alone, how can I get two values from the callback function
#include <open62541/plugin/log_stdout.h>
#include <open62541/server.h>
#include <open62541/server_config_default.h>
#include <signal.h>
#include <stdlib.h>
static void
updateCurrentTime(UA_Server *server) {
UA_DateTime now = UA_DateTime_now();
UA_Variant value;
UA_Variant_setScalar(&value, &now, &UA_TYPES[UA_TYPES_DATETIME]);
UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-value-callback");
UA_Server_writeValue(server, currentNodeId, value);
}
static void
addCurrentTimeVariable(UA_Server *server) {
UA_DateTime now = 0;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("en-US", "Current time - value callback");
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
UA_Variant_setScalar(&attr.value, &now, &UA_TYPES[UA_TYPES_DATETIME]);
UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-value-callback");
UA_QualifiedName currentName = UA_QUALIFIEDNAME(1, "current-time-value-callback");
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
UA_Server_addVariableNode(server, currentNodeId, parentNodeId,
parentReferenceNodeId, currentName,
variableTypeNodeId, attr, NULL, NULL);
updateCurrentTime(server);
}
/**
* Variable Value Callback
* ^^^^^^^^^^^^^^^^^^^^^^^
*
* When a value changes continuously, such as the system time, updating the
* value in a tight loop would take up a lot of resources. Value callbacks allow
* to synchronize a variable value with an external representation. They attach
* callbacks to the variable that are executed before every read and after every
* write operation. */
static void
beforeReadTime(UA_Server *server,
const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *nodeid, void *nodeContext,
const UA_NumericRange *range, const UA_DataValue *data) {
updateCurrentTime(server);
}
static void
afterWriteTime(UA_Server *server,
const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *nodeId, void *nodeContext,
const UA_NumericRange *range, const UA_DataValue *data) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"The variable was updated");
cout<<"Field value is "<< *(double*)data->value.data<<endl;
}
static void
addValueCallbackToCurrentTimeVariable(UA_Server *server) {
UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-value-callback");
UA_ValueCallback callback ;
callback.onRead = beforeReadTime;
callback.onWrite = afterWriteTime;
UA_Server_setVariableNode_valueCallback(server, currentNodeId, callback);
}
/**
* Variable Data Sources
* ^^^^^^^^^^^^^^^^^^^^^
*
* With value callbacks, the value is still stored in the variable node.
* So-called data sources go one step further. The server redirects every read
* and write request to a callback function. Upon reading, the callback provides
* a copy of the current value. Internally, the data source needs to implement
* its own memory management. */
static UA_StatusCode
readCurrentTime(UA_Server *server,
const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *nodeId, void *nodeContext,
UA_Boolean sourceTimeStamp, const UA_NumericRange *range,
UA_DataValue *dataValue) {
UA_DateTime now = UA_DateTime_now();
UA_Variant_setScalarCopy(&dataValue->value, &now,
&UA_TYPES[UA_TYPES_DATETIME]);
dataValue->hasValue = true;
return UA_STATUSCODE_GOOD;
}
static UA_StatusCode
writeCurrentTime(UA_Server *server,
const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *nodeId, void *nodeContext,
const UA_NumericRange *range, const UA_DataValue *data) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Changing the system time is not implemented");
return UA_STATUSCODE_BADINTERNALERROR;
}
static void
addCurrentTimeDataSourceVariable(UA_Server *server) {
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("en-US", "Current time - data source");
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-datasource");
UA_QualifiedName currentName = UA_QUALIFIEDNAME(1, "current-time-datasource");
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
UA_DataSource timeDataSource;
timeDataSource.read = readCurrentTime;
timeDataSource.write = writeCurrentTime;
UA_Server_addDataSourceVariableNode(server, currentNodeId, parentNodeId,
parentReferenceNodeId, currentName,
variableTypeNodeId, attr,
timeDataSource, NULL, NULL);
}
static UA_DataValue *externalValue;
static void
addCurrentTimeExternalDataSource(UA_Server *server) {
UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-external-source");
UA_ValueBackend valueBackend;
valueBackend.backendType = UA_VALUEBACKENDTYPE_EXTERNAL;
valueBackend.backend.external.value = &externalValue;
UA_Server_setVariableNode_valueBackend(server, currentNodeId, valueBackend);
}
/** It follows the main server code, making use of the above definitions. */
static volatile UA_Boolean running = true;
static void stopHandler(int sign) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
running = false;
}
int main(void) {
signal(SIGINT, stopHandler);
signal(SIGTERM, stopHandler);
UA_Server *server = UA_Server_new();
UA_ServerConfig_setDefault(UA_Server_getConfig(server));
addCurrentTimeVariable(server);
addValueCallbackToCurrentTimeVariable(server);
addCurrentTimeDataSourceVariable(server);
addCurrentTimeExternalDataSource(server);
UA_StatusCode retval = UA_Server_run(server, &running);
UA_Server_delete(server);
return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}
Footer
© 2022 GitHub, Inc.
Footer navigation
Terms
Privacy
Security
Status
Docs
Contact GitHub
Pricing
API
Training
Blog
About
open62541/tutorial_server_datasource.c at master · open62541/open62541 · GitHub

How to include the size of array into the for loop without triggering error

This is the login function that I want to implement.
The problem is that I want to use the syntax of sizeof(id) in the for loop without triggering error.
Any solution??
int login();
int login()
{
int i, att, num_i, status;
att = 1;
status = 0;
num_i = 999;
char* id[100], * pass[100];
char* inp_id[100], inp_pass[100];
id[0] = "id1"; ///Sample ID
id[1] = "id2";
id[2] = "id3";
pass[0] = "pass1"; ///Sample pass
pass[1] = "pass2";
pass[2] = "pass3";
while (att <= 3)
{
printf("ID:");
scanf("%s", &inp_id);
for (i = 0; i < 3; ++i) /// I wanted this to repeat accordingly to the size of ID that was stored
{
if (strcmp(inp_id, id[i]) == 0) /// Cuz when I declare i > 100 when it call for i[4] and it doesn't exist, error occured.
{
num_i = i;
break; /// wanted it to break out of the loop once it got the id that's similar to what was entered
}
}
printf("Password:");
scanf("%s", &inp_pass);
if (num_i < 100)
{
if (strcmp(inp_pass, pass[num_i]) == 0)///checking pass according to the positon of i on the ID
{
status = 1;
att = 999;
}
}
att++;
}
I've deleted a portion of the code due to it asking for more information.
A simplified example of what I described in my comment:
Or at least these are components to help you understand.
struct account {
char *id;
char *pass;
};
static const struct account account_list[] = {
{ .id = "id1", .pass = "pass1" },
{ .id = "id2", .pass = "pass2" },
{ .id = "id3", .pass = "pass3" },
{ NULL },
};
struct account *a;
for (a = account_list; a.id; a++) {
....
}
Something like this is much easier to work with.

How can I set a user custom pointer in libwebsockets callback?

How can I set a user custom pointer in libwebsockets callback?
I added a pointer variable into a lws_protocol.
When callback function is called, user pointer is always NULL.
I use libwebsockets v3.0.
static int interrupted, rx_seen, test;
int ws_callback(struct lws *ws, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
// user is NULL
return lws_callback_http_dummy(ws, reason, user, in, len);
}
int main() {
struct lws *ws;
struct lws_context_creation_info context_info;
struct lws_client_connect_info client_info;
struct lws_context *context;
struct lws_protocols protocols[] = {
{ "ws_callback", ws_callback, 0, 0, 0, POINTER_VARIABLE /* HERE */, 0 }
};
int n = 0;
// context creation info
memset(&context_info, 0, sizeof(context_info));
context_info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
context_info.port = CONTEXT_PORT_NO_LISTEN;
context_info.protocols = protocols;
context = lws_create_context(&context_info);
if (!context) {
return;
}
memset(&client_info, 0, sizeof(client_info));
client_info.context = context;
client_info.port = 8080;
client_info.address = "192.168.1.1";
client_info.path = "/";
client_info.host = client_info.address;
client_info.origin = client_info.address;
client_info.protocol = protocols[0].name;
client_info.pwsi = &ws;
lws_client_connect_via_info(&client_info);
while (n >= 0 && ws && !interrupted) {
n = lws_service(context, 1000);
}
lws_context_destroy(context);
return 0;
}
You must specify the size of per session data structure, but not the pointer itself. Per session data will be different for each connection.
typedef struct per_session_data {
void *user_space;
} per_session_data;
int ws_callback(struct lws *ws, enum lws_callback_reasons reason, void *user, void *in, size_t len)
{
/* This will be different for every connected peer */
per_session_data *data = (per_session_data*)user;
}
struct lws_protocols protocols[] = {
{ "ws_callback", ws_callback, sizeof(per_session_data), 0 }
{ NULL, NULL, 0, 0 } /* terminator */
};
You can also set optional user pointer that will be associated with the context. lws_context_creation_info has user variable for userspace. You must set it before creating the context
typedef struct per_session_data {
void *user_space;
/*
Same other variables
*/
} per_session_data;
int ws_callback(struct lws *ws, enum lws_callback_reasons reason, void *user, void *in, size_t len)
{
/* This will be different for every connected peer */
per_session_data *data = (per_session_data*)user;
/* This will be same for every connected peer */
void *userdata = lws_context_user(lws_get_context(ws));
/* userdata is POINTER_VARIABLE specified before context creating */
switch (reason)
{
case LWS_CALLBACK_ESTABLISHED:
/* Initialize per session data here */
break;
case LWS_CALLBACK_CLOSED:
/* Destroy per session data here */;
break;
default:
break;
}
}
struct lws_protocols protocols[] = {
{ "ws_callback", ws_callback, sizeof(per_session_data), 0 }
{ NULL, NULL, 0, 0 } /* terminator */
};
int main()
{
/*
your code here
*/
// context creation info
memset(&context_info, 0, sizeof(context_info));
context_info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
context_info.port = CONTEXT_PORT_NO_LISTEN;
context_info.protocols = protocols;
context_info.user = POINTER_VARIABLE; /* HERE */
context = lws_create_context(&context_info);
if (!context) {
return;
}
/*
your code here
*/
}

Compile-errors: "creating array with negative size ('-0x00000000000000001')", "assignment of read-only location"

Hi I'm new to GoogleMock but not new to mocking (I've python experience).
For a C-code based interface we want to use Googlemock. Up to compiling everything goes smoothly. No problems with defining the C-based code:
mock-header-file
#include "gmock/gmock.h"
extern "C"
{
#include "interface/interfacetype.h"
}
struct HELPER
{
virtual ~HELPER() {}
virtual int interface_func( ID_ENUM_TYPE id, MY_STRUCT_TYPE *params) = 0;
};
struct INTERFACE_MOCK : public HELPER
{
MOCK_METHOD2( interface_func, int( ID_ENUM_TYPE id, MY_STRUCT_TYPE *params) );
};
extern INTERFACE_MOCK *mock_create_mock();
extern void mock_delete_mock();
mock-implementation:
#include mock.h
extern "C"
{
#include "interface/interfacetype.h"
}
INTERFACE_MOCK *interface_2_mock = NULL;
extern "C"
{
int interface_func( ID_ENUM_TYPE id, MY_STRUCT_TYPE *params )
{
return interface_2_mock->interface_func( id, params );
}
}
INTERFACE_MOCK *mock_create_mock()
{
if ( interface_2_mock == NULL )
{
interface_2_mock = new( INTERFACE_MOCK );
}
return interface_2_mock;
}
void mock_delete_mock()
{
delete interface_2_mock;
}
MY_STRUCT_TYPE is as follows:
typedef struct my_struct_tag
{
float value[196]
} MY_STRUCT_TYPE
unittest-code is as follows:
INTERFACE_MOCK *interface_2_mock;
class fixture : public ::testing::Test
{
protected:
virtual void SetUp()
{
interface_2_mock = mock_create_mock();
}
virtual void TearDown()
{
mock_delete_mock();
}
};
TEST_F( fixture, test_case )
{
MY_STRUCT_TYPE params;
int result = 0;
for ( int i=0; i<196; i++)
{
params.value[i] = 1.23;
}
// I'm only interested in checking that function is called,
// mocking the return-value and mocking 'params' which is an output-param
EXPECT_CALL( *interface_2_mock, interface_func( _, _ ) )
.Times(2)
.WillRepeatedly( DoAll( SetArgReferee<1>( &params ), return 0 ) ) );
// Call function_under_test which calls interface_func
result = function_under_test();
ASSERT_EQ( 0, result ) << "Return-value " << result << " not as expected"
}
When compiling this all goes well until the EXPECT_CALL line is compiled. There we have the following error which we do not understand:
Rebuilding "<target>.oppsparc" on host "<host>"
======== Finished "<target>.oppsparc" on host "<host>" ========
Sun native compile : test_my_test.cpp to test_my_test.oppsparc
In file included from ./gmock/gmock.h:65,
from mock/interface_2_mock.hpp:33,
from test_my_test.cpp:23:
./gmock/gmock-more-actions.h: In member function 'typename testing::internal::Function<F>::Result testing::SetArgRefereeActionP<k, value_type>::gmock_Impl<F>::gmock_PerformImpl(const typename testing::internal::Function<F>::ArgumentTuple&, arg0_type, arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, arg9_type) const [with arg0_type = ID_ENUM_TYPE , arg1_type = MY_STRUCT_TYPE*, arg2_type = testing::internal::ExcessiveArg, arg3_type = testing::internal::ExcessiveArg, arg4_type = testing::internal::ExcessiveArg, arg5_type = testing::internal::ExcessiveArg, arg6_type = testing::internal::ExcessiveArg, arg7_type = testing::internal::ExcessiveArg, arg8_type = testing::internal::ExcessiveArg, arg9_type = testing::internal::ExcessiveArg, F = void( ID_ENUM_TYPE , MY_STRUCT_TYPE*), int k = 1, value_type = MY_STRUCT_TYPE*]':
./gmock/gmock-generated-actions.h:664: instantiated from 'static Result testing::internal::ActionHelper<Result, Impl>::Perform(Impl*, const std::tr1::tuple<_U1, _U2>&) [with A0 = ID_ENUM_TYPE , A1 =MY_STRUCT_TYPE*, Result = void, Impl = testing::SetArgRefereeActionP<1, MY_STRUCT_TYPE*>::gmock_Impl<void( ID_ENUM_TYPE ,MY_STRUCT_TYPE*)>]'
./gmock/gmock-more-actions.h:170: instantiated from 'typename testing::internal::Function<F>::Result testing::SetArgRefereeActionP<k, value_type>::gmock_Impl<F>::Perform(const typename testing::internal::Function<F>::ArgumentTuple&) [with F = void( ID_ENUM_TYPE , MY_STRUCT_TYPE*), int k = 1, value_type = MY_STRUCT_TYPE*]'
test_my_test.cpp:251: instantiated from here
./gmock/gmock-more-actions.h:175: error: creating array with negative size ('-0x00000000000000001')
./gmock/gmock-more-actions.h:177: error: assignment of read-only location 'std::tr1::get [with int __i = 1, _Elements = ID_ENUM_TYPE, MY_STRUCT_TYPE*](((const std::tr1::tuple<ID_ENUM_TYPE, MY_STRUCT_TYPE*>&)((const std::tr1::tuple<ID_ENUM_TYPE, MY_STRUCT_TYPE*>*)args)))'
*** Error code 1
========================================================
Aborting...
Can you help us?
/* edit */ I saw that I left out the fixture
This time I found the answer. Instead of SetArgReferee<1>( &params ), I've should have used SetArgPointee<1>( params )

Passing a value with struct type into a function in C

typedef struct {
nat id;
char *data;
} element_struct;
typedef element_struct * element;
void push(element e, queue s) {
nat lt = s->length;
if (lt == max_length - 1) {
printf("Error in push: Queue is full.\n");
return;
}
else {
s->contents[lt] = e;
s->length = lt + 1;
}
}
int main () {
push(something_of_type_element, s);
}
How would i go about formatting "something_of_type_element"?
Thanks
Notes:
nat is the same as int
How about:
element elem = malloc(sizeof(element_struct));
if (elem == NULL) {
/* Handle error. */
}
elem->id = something;
elem->data = something_else;
push(elem, s);
Note that there's lots of memory management missing here...
Like this:
element_struct foo = { 1, "bar" };
push(&foo, s);
If you have a C99 compiler you can do this:
element_struct foo = {
.id = 1,
.data = "bar"
};
push(&foo, s);
Note that the data in the structure must be copied if it needs to live longer than the scope in which it was defined. Otherwise, memory can be allocated on the heap with malloc (see below), or a global or static variable could be used.
element_struct foo = malloc(sizeof (element_struct));
foo.id = 1;
foo.data = "bar";
push(foo, s);

Resources