What Does (void *) Mean When Used To Set The Arguments For A Function

What does (void *) mean when used to set the arguments for a function Projects Programming January 12, 2022, 7:26am 1

This is probably more a "C language" question than something that is Arduino-specific but I still don't understand it as my extensive programming experience involves little exposure to this group of languages.

I have been trying to learn about the Arduino timer and I notice that functions that are called by timers are often defined with this type of argument and all works fine when used in this manner. However, I have tried to call such a function in a simple call not involving timers and I can't work out what to include as the argument in the call. I have tried nothing, a boolean variable and a few other things and can't get past compile.

January 12, 2022, 7:29am 2

Please post an example sketch that illustrates your question so that it can be seen in context

January 12, 2022, 8:33am 3

This compiles (and works).

// Include necessary library files #include <ESP8266WiFi.h> #include <arduino-timer.h> // Timer objects auto OutputTimer = timer_create_default(); void setup () { // Call CT read function once per minute. OutputTimer.every(60000, ReadCT); } void loop() { OutputTimer.tick(); } bool ReadCT(void *) { Serial.println( "Entered ReadCT" ); // Call current transformer reader and send reading to server return true; }

When I try and add an extra call to ReadCT in front of the timer-based one

... bool bolJunk; void setup () { // Call CT read function once per minute. bolJunk = ReadCT(); OutputTimer.every(10000, ReadCT); ...

I can't get it to compile. I have tried putting all sorts of things inside the argument space of the call and it still won't compile.

I just want the first execution to be NOW rather than after a minute which is the default behaviour.

Yay!! As a part of putting together these cut-down sketches for the forum, I thought to try dropping the brackets from after the new call and this compiled.

Clearly what (void *) in the definition means (at least in part) is that you can call it without brackets in the call statement. If only I could find a document that told me that.

January 12, 2022, 8:40am 4 downibri:

I have tried putting all sorts of things inside the argument space of the call and it still won't compile.

Such as what? The parameter needs to be something with type void*. That means a pointer to... something/anything.

January 12, 2022, 8:40am 5

you can send nullptr in this case

ReadCT(nullptr);

January 12, 2022, 8:44am 6 downibri:

Clearly what (void *) in the definition means (at least in part) is that you can call it without brackets in the call statement.

No. If you leave off the brackets, the function does not get called.

bolJunk = ReadCT;

simply assigns, to the variable boljunk, a pointer to the function ReadCT. Since booljunk is a Boolean, it can't hold the function pointer and probably always gets set to true I suspect.

January 12, 2022, 8:59am 7 downibri:

bool ReadCT(void *)

"void *" means "a pointer to "something not tightly specified." A sort of hole in C's "strong typing."

It's frequently used for "callbacks" from service routines, in the sense that if you have a low-level timer alarm function, you can register a function for the low level call, without the low-level call needing to know the details of how the higher level code works. The pointer CAN be to a struct containing a large amount of data.

In your example, it might look like:

void setup() { // call ReadCT every 60s with a pointer to Serial as it's argument OutputTimer.every(60000, ReadCT, (void *)&Serial); } bool ReadCT(void *arg) { Stream *output = (Stream *)arg; // our argument was an output stream. Make it so. output->print("Entered ReadCT"); // output message to the defined stream. }

If the ReadCT() that you've defined doesn't need any arguments, then you can just pass null, or nulptr, or 0, or whatever. But if it's expecting a particular pointer, you had better provide that type of pointer! eg:

ReadCT((void *)&Serial3);

(In C, the casts to (void *) would not be necessary. I think (but am not sure) that C++ is fussier.)

January 12, 2022, 9:17am 8

It’s a generic pointer

See https://www.learncpp.com/cpp-tutorial/void-pointers/

As they say

C++ actually offers a much better way to do the same thing (via function overloading) that retains type checking to help prevent misuse. Many other places where void pointers would once be used to handle multiple data types are now better done using templates, which also offer strong type checking.

So if you can avoid this, it is better to do so but if this is what you need to deal with then…

January 12, 2022, 11:33am 9

i've often used void * as the argument type to function ptrs in tables to allow a generic typedef to be used for multiple purpose. those functions would cast the arg as needed

the advantage of passing an argument as a ptr is that is usually the largest size variable possible and void suggests this purpose (i.e. slang)

a trivial example

// // example state machine // #include <stdio.h> #include "stateMach.h" // ------------------------------------------------ Status a (void* a) { printf ("%s:\n", __func__); return OK; } // ------------------------------------------------ Status b (void* a) { printf ("%s:\n", __func__); return OK; } // ------------------------------------------------ Status c (void* a) { printf ("%s:\n", __func__); return OK; } // ------------------------------------------------ Status __ (void* a) { printf ("%s:\n", __func__); return OK; } // -------------------------------------------------------------------- #define N_STATE 3 #define N_STIM 2 typedef enum { S0, S1, S2 } State_t; typedef Status(*Action_t)(void*) ; State_t smTransitionTbl [N_STATE] [N_STIM] = { { S1, S2, }, { S0, S2, }, { S2, S1, }, }; Action_t smActionTbl [N_STATE] [N_STIM] = { { a, b }, { c, __ }, { __, a }, }; // ------------------------------------------------ char *msg1 [] = { "State machine has 3 states and 2 stimuli.", "It has the following state transistion and action routine tables.", "A __() represents do nothing and is easily identified in table.", "Each row is indexed by a state and each column a stimulus.", "Of course, meaningful action routine names are helpful.", }; char *msg2 [] = { "Enter valid stimuli [0-1]:" }; void smHelp (void) { for (int i = 0; i < sizeof(msg1)/sizeof(char*); i++) printf (" %s\n", msg1 [i]); for (int state = 0; state < N_STATE; state++) { printf ("%8s", ""); for (int stim = 0; stim < N_STIM; stim++) printf (" %d", smTransitionTbl [state][stim]); printf ("%8s", ""); for (int stim = 0; stim < N_STIM; stim++) { if (a == smActionTbl [state][stim]) printf (" a()"); else if (b == smActionTbl [state][stim]) printf (" b()"); else if (c == smActionTbl [state][stim]) printf (" c()"); else printf (" __()"); } printf ("\n"); } for (int i = 0; i < sizeof(msg2)/sizeof(char*); i++) printf (" %s\n", msg2 [i]); } // ------------------------------------------------ static State_t _smState = S0; Status smEngine (Stim_t stim) { Action_t func; State_t last = _smState; if (N_STIM <= stim) return ERROR; func = smActionTbl [_smState] [stim]; _smState = smTransitionTbl [_smState] [stim]; printf (" stim %d, transition from state %d to %d, exec ", stim, last, _smState); return (*func) (NULL); } January 12, 2022, 11:42am 10

@gcjr interesting example.

gcjr:
for (int i = 0; i < sizeof(msg1)/sizeof(char*); i++) printf (" %s\n", msg1 [i]);

you could use a string literal to make your life easier!

// see https://en.cppreference.com/w/cpp/language/string_literal const char* s1 = R"___( State machine has 3 states and 2 stimuli. It has the following state transistion and action routine tables. A __() represents do nothing and is easily identified in table. Each row is indexed by a state and each column a stimulus. Of course, meaningful action routine names are helpful. )___"; void setup() { Serial.begin(115200); Serial.println(); Serial.println(s1); } void loop() {}

the IDE does not recognise that too well, so auto-indent is fucked up afterwards thus it's best defined in a separate .h and imported into the main code

January 12, 2022, 12:23pm 11

that code must be 20 years old.

January 12, 2022, 12:47pm 12

this explains why :slight_smile:

string literal appeared formally in August 2011 (C++11) if I remember correctly

July 11, 2022, 12:47pm 13

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.

Topic Replies Views Activity
Diferencias entre Funcion() y Funcion(void *) Español 3 68 February 21, 2026
Void STOP (void) - Bedeutung Deutsch 13 161 September 24, 2025
Used Void and then did not use Void? I don't understand why? Programming 5 135 May 29, 2025
New Il tempo delle librerie è finito.... Software 18 1240 May 7, 2021
How can i add new [voids] functions to my code? Programming 27 547 January 29, 2026
Unfortunately, your browser is unsupported. Please switch to a supported browser to view rich content, log in and reply.

Tag » What Does Void Mean In Arduino