If I had some enums like
typedef enum {
AN_TRISTATE_0,
AN_TRISTATE_1,
AN_NOTHING,
AN_MOTOR_1,
AN_MOTOR_2,
AN_MOTOR_3,
AN_SENSOR_1,
AN_SENSOR_2,
AN_SENSOR_3,
AN_SENSOR_4,
AN_SENSOR_5
} adc_pin_func_t;
and
adc_pin_func_t a_particular_pin = ...
, would it be possible it check if the pin is part of a particular group, e.g pin is part of AN_MOTOR or part of AN_SENSOR, instead of having to check against each item in each possible group.
Or are there more efficient ways of doing this, other than using enums?
Thanks in advance
You could create masks for each of the groups:
typedef enum {
AN_TRISTATE_0 = 0x00001,
AN_TRISTATE_1 = 0x00002,
AN_TRISTATE_MASK = 0x0000f,
AN_NOTHING = 0x00010, // Should this be 0x00000 ?
AN_MOTOR_1 = 0x00100,
AN_MOTOR_2 = 0x00200,
AN_MOTOR_3 = 0x00400,
AN_MOTOR_MASK = 0x00f00,
AN_SENSOR_1 = 0x01000,
AN_SENSOR_2 = 0x02000,
AN_SENSOR_3 = 0x04000,
AN_SENSOR_4 = 0x08000,
AN_SENSOR_5 = 0x10000,
AN_SENSOR_MASK = 0xff000
} adc_pin_func_t;
And then simply test a group against the mask using the & operator:
if (a_particular_pin & AN_SENSOR_MASK)
{
// it's a sensor pin
}
else if (a_particular_pin & AN_MOTOR_MASK)
{
// it's a motor pin
}
EDIT: As others have suggested using a range, then you could probably create a macro for the test, which would allow you to change how the test is performed without the need to change the code (always a good thing):
#define IS_AN_SENSOR(x) (((x) & AN_SENSOR_MASK) != 0)
#define IS_AN_MOTOR(x) (((x) & AN_MOTOR_MASK) != 0)
// etc.
and then the test becomes:
if (IS_AN_SENSOR(a_particular_pin))
{
// it's a sensor pin
}
else if (IS_AN_MOTOR(a_particular_pin))
{
// it's a motor pin
}
// etc
If you then needed to change to using a range then only the macros need to change (and you'd obviously need to define the range min/max):
#define IS_AN_SENSOR(x) ((x) >= AN_SENSOR_START && (x) <= AN_SENSOR_END)
// etc
You are free to choose your enum values, so you could do something like this
typedef enum {
AN_TRISTATE_0 = 0x0001,
AN_TRISTATE_1 = 0x0002,
AN_NOTHING = 0x0000,
AN_MOTOR_1 = 0x0010,
AN_MOTOR_2 = 0x0020,
AN_MOTOR_3 = 0x0030,
AN_SENSOR_1 = 0x0100,
AN_SENSOR_2 = 0x0200,
AN_SENSOR_3, /*and so on*/
AN_SENSOR_4,
AN_SENSOR_5
} adc_pin_func_t;
Then you can compare bits to check categories. For example, a motor type is the only category that will have non-zero (AN_MOTOR_2 & 0x00F0)
You can do a
typedef enum {
AN_TRISTATE_START,
AN_TRISTATE_0 = AN_TRISTATE_START,
AN_TRISTATE_1,
AN_TRISTATE_END = AN_TRISTATE_1,
AN_NOTHING,
AN_MOTOR_START,
AN_MOTOR_1 = AN_MOTOR_START,
AN_MOTOR_2,
AN_MOTOR_3,
AN_MOTOR_END = AN_MOTOR_3,
AN_SENSOR_START,
AN_SENSOR_1 = AN_SENSOR_START,
AN_SENSOR_2,
AN_SENSOR_3,
AN_SENSOR_4,
AN_SENSOR_5,
AN_SENSOR_END = AN_SENSOR_5
} adc_pin_func_t;
bool inline
is_sensor(int pin)
{
return AN_SENSOR_START <= pin
&& pin <= AN_SENSOR_END
}
and then in your code
if ( is_sensor(pin) )
{
/* body */
}
This way you don't have to care about masking particular values. May be useful if groups contain a lot of values.
You can give values to the enum in exponents of 2. Then you can simply use bitwise AND and OR masks. So you can assign values like 1,2,4,8,16,32... so on.
typedef enum {
AN_TRISTATE_0 = 1,
AN_TRISTATE_1 = 2,
AN_NOTHING = 4,
AN_MOTOR_1 = 8,
AN_MOTOR_2 = 16,
AN_MOTOR_3 = 32,
AN_SENSOR_1 = 64,
AN_SENSOR_2 = 128,
AN_SENSOR_3 = 256,
AN_SENSOR_4 = 512,
AN_SENSOR_5 = 1024
} adc_pin_func_t;
Then for checking with motor type, you can AND with (32+16+8) = 56. So pin & 56, if non zero will mean it is of motor type.
If you really like to have some modularity in your enum (the "hard coded" enum values are also a valid method), you can implement a struct with some OOP flavour. The design become more complicated, but the usage is still simple :
#include <stdio.h>
#include <string.h>
// Every enum will have its first value start at the value of the previous enum's last member PLUS ONE
#define OFFSET_ENUM_MOTOR ( sizeof(adc_pin_tristate_t) )
#define OFFSET_ENUM_SENSOR ( OFFSET_ENUM_MOTOR + sizeof(adc_pin_motor_t) )
///////////////////////////////////////////////////////////////////////////////
// Enum
typedef enum {
AN_TRISTATE_0,
AN_TRISTATE_1,
AN_NOTHING
} adc_pin_tristate_t;
typedef enum {
AN_MOTOR_1 = OFFSET_ENUM_MOTOR,
AN_MOTOR_2,
AN_MOTOR_3
} adc_pin_motor_t;
typedef enum {
AN_SENSOR_1 = OFFSET_ENUM_SENSOR,
AN_SENSOR_2,
AN_SENSOR_3,
AN_SENSOR_4,
AN_SENSOR_5
} adc_pin_sensor_t;
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Struct for abstraction
typedef struct adc_pin_func2_t{
// our "enum value"
unsigned int enum_id;
// return is the enum is a motor one
int(*isMotor)(struct adc_pin_func2_t*);
} adc_pin_func2_t;
// Struct
///////////////////////////////////////////////////////////////////////////////
// Member methods : return if the enum is a motor one
int
PinFunc_isMotor(
adc_pin_func2_t *This /* object */
)
{
return ( (This->enum_id>=OFFSET_ENUM_MOTOR) && (This->enum_id<OFFSET_ENUM_SENSOR) );
}
// Creation of the structure
// Initialization
static void
PinFunc_Init(
adc_pin_func2_t *This, /* output */
unsigned int identifier /* old enum identifier */
)
{
// copy members
This->enum_id = identifier;
//copy methods (do not forget to do it !)
This->isMotor = PinFunc_isMotor;
}
// Constructor
adc_pin_func2_t
PinFunc_Create(
unsigned int identifier /* old enum identifier */
)
{
adc_pin_func2_t This;
PinFunc_Init(&This, identifier);
return This;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
main()
{
adc_pin_func2_t pin = PinFunc_Create(AN_NOTHING);
printf("%d \n", pin );
printf("%d \n", pin.isMotor(&pin) );
adc_pin_func2_t pin2 = PinFunc_Create(AN_MOTOR_2);
printf("%d \n", pin2 );
printf("%d \n", pin2.isMotor(&pin2) );
}
The usage of members functions like pin.isMotor(&pin) isn't very elegant (we repeat pin), but it is a shortcoming of C, which is not an OOP language.
If you don't want to have to manually maintain non-overlapping values, then you can very nearly get it all handled for you automatically. The only thing you'll have to figure out is the maximum number of bits in a group:
#define PIN_GROUP_SHIFT 4
#define GET_PIN_GROUP(x) (adc_pin_group_t)((y) >> PIN_GROUP_SHIFT)
#define PIN_GROUP_START(x) XX_GROUP_##x = ((GROUP_##x << PIN_GROUP_SHIFT) - 1),
enum {
GROUP_TRISTATE,
GROUP_NOTHING,
GROUP_MOTOR,
GROUP_SENSOR
} adc_pin_group_t;
typedef enum {
PIN_GROUP_START(TRISTATE)
AN_TRISTATE_0,
AN_TRISTATE_1,
PIN_GROUP_START(NOTHING)
AN_NOTHING,
PIN_GROUP_START(MOTOR)
AN_MOTOR_1,
AN_MOTOR_2,
AN_MOTOR_3,
PIN_GROUP_START(SENSOR)
AN_SENSOR_1,
AN_SENSOR_2,
AN_SENSOR_3,
AN_SENSOR_4,
AN_SENSOR_5
} adc_pin_func_t;
To determine the type of an entry in the enum, use GET_PIN_GROUP(x), and compare it to whichever value of the adc_pin_group_t enum. You can even switch on the result, if that's helpful.
However, that AN_NOTHING entry makes me wonder if your enum is meant to line up with specific values for each entry. are specific values associated with the pins, which you may not be able to assign arbitrarily. In that case you might need to try something complicated (which I haven't tested):
#define GET_PIN_VALUE(x) ((x) & ((1 << PIN_GROUP_SHIFT) - 1)
#define PIN_GROUP_START(x) \
WW_GROUP_##x, \
XX_GROUP_##x = (GROUP_##x << PIN_GROUP_SHIFT) \
+ GET_PIN_INDEX(WW_GROUP_##x) - 1,
Where you need to know the value that your original enum would have used, use GET_PIN_INDEX(x).
Related
I am currently using "STM32F429I-DISC1" with joystick. I am trying to draw something on the LCD screen and using joystick move this object. My drawing is working fine, but I have the error: " void value not ignored as it ought to be".
This two lines have problems...
localX = Joy_ReadXY(CTRL_REG_IN3);
localY = Joy_ReadXY(CTRL_REG_IN4);
Can someone please tell me, how I can fix this error?
And why I see this error?
Main.c
#include "stm32f429i_discovery_lcd.h"
#define CTRL_REG_IN3 0b00011000
#define CTRL_REG_IN4 0b00100000
SemaphoreHandle_t xMutex;
Joystick_data xy;
void vTaskFunction1(void *pvParameters) {
uint16_t localX;
uint16_t localY;
for(;;) {
localX = Joy_ReadXY(CTRL_REG_IN3);
localY = Joy_ReadXY(CTRL_REG_IN4);
xSemaphoreTake( xMutex, portMAX_DELAY );
xy.x = localX;
xy.y = localY;
xSemaphoreGive( xMutex );
HAL_Delay(10);
}
}
void vTaskFunction2(void *pvParameters) {
uint32_t xCoord = 240/2;
uint32_t yCoord = 320/2;
uint8_t reads = 0;
uint8_t ballRadius = 5;
uint16_t xLimitMin = ballRadius+25;
uint16_t xLimitMax = 240-ballRadius-25;
uint16_t yLimitMin = ballRadius+25;
uint16_t yLimitMax = 320-ballRadius-25;
for(;;) {
xSemaphoreTake( xMutex, portMAX_DELAY );
if (xy.x > 3000 && !(xCoord < xLimitMin))
xCoord -= 5;
if (xy.x < 1000 && !(xCoord > xLimitMax))
xCoord += 5;
if (xy.y > 3000 && !(yCoord < yLimitMin))
yCoord -= 5;
if (xy.y < 1000 && !(yCoord > yLimitMax))
yCoord += 5;
reads++;
BSP_LCD_Clear(LCD_COLOR_WHITE);
BSP_LCD_DrawCircle(xCoord, yCoord, ballRadius);
BSP_LCD_FillCircle(xCoord, yCoord, ballRadius);
xSemaphoreGive(xMutex);
HAL_Delay(20);
}
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI4_Init();
MX_TIM1_Init();
MX_USART1_UART_Init();
// LCD Things
BSP_LCD_Init();
BSP_LCD_LayerDefaultInit(1, LCD_FRAME_BUFFER);
BSP_LCD_SelectLayer(1);
BSP_LCD_SetBackColor(LCD_COLOR_WHITE); // Vali meelepärane värv
BSP_LCD_Clear(LCD_COLOR_WHITE);
BSP_LCD_SetTextColor(LCD_COLOR_DARKBLUE); // Vali meelepärane värv
MX_FREERTOS_Init();
if ( xMutex == NULL )
{
xMutex = xSemaphoreCreateMutex();
if ( ( xMutex ) != NULL )
xSemaphoreGive( ( xMutex ) );
}
xTaskCreate(vTaskFunction1, "Task 1", 100, NULL, 1, NULL);
xTaskCreate(vTaskFunction2, "Task 2", 100, NULL, 1, NULL);
vTaskStartScheduler();
osKernelStart();
while (1)
{
}
}
Read joystick function (joystick.c)
#include <stdio.h>
#include <main.h>
#include "gpio.h"
#include "spi.h"
#define READ_SLAVE_OPERATION 0b10000000
#define READ_INCR_SLAVE_OPERATION 0b11000000
#define WRITE_SLAVE_OPERATION 0b00000000
#define CTRL_REG_IN3 0b00000011
#define CTRL_REG_IN4 0b00000100
#define OUT_X_L 0x28
#define OUT_X_H 0x29
#define OUT_Y_L 0x2A
#define OUT_Y_H 0x2B
#define OUT_Z_L 0x2C
#define OUT_Z_H 0x2D
#define JOY_CS_LOW() HAL_GPIO_WritePin(JOY_CS_GPIO_PORT, JOY_CS_PIN, 0)
#define JOY_CS_HIGH() HAL_GPIO_WritePin(JOY_CS_GPIO_PORT, JOY_CS_PIN, 1)
#define JOY_CS_GPIO_PORT GPIOC
#define JOY_CS_PIN GPIO_PIN_13
int16_t Joy_ReadXY(uint8_t reg1){
uint8_t pTxData1[2] = {reg1, 0};
uint8_t pRxData1[2] = {0, 0};
JOY_CS_LOW();
HAL_SPI_TransmitReceive(&hspi4, pTxData1, pRxData1, 2, HAL_MAX_DELAY);
JOY_CS_HIGH();
return pRxData1[0] << 8 | pRxData1[1];
}
Here, in Main.c, you call the function before telling the compiler about what parameters and what return value types it has.
localX = Joy_ReadXY(CTRL_REG_IN3);
localY = Joy_ReadXY(CTRL_REG_IN4)
That confused the compiler and it starts "guessing" about them.
Guessing that it is a void-returning function, the compiler then complains that you are expecting a return value from a function which does return void i.e. nothing.
The returned void should be ignored, instead of attempting to write it to a variable. At least that is what the compiler thinks...
To fix it, you should explain to the compiler that there is a function elsewhere, with name, parameters and return value type. That is done by providing the prototype
int16_t Joy_ReadXY(uint8_t reg1);
It needs to be done before the function body in which the the extern function is first called. (And you already confirmed in comments that it fixes the described problem in your code.)
Note that for the other shown functions this is not needed, because they are defined (with head and body) before they are called.
Similar for other functions, which have their prototype provided in the header you include early on.
Actually, putting the prototype of your function into a header and including that similarily would be the best way to solve this.
I want to prevent invalid value enum assignment. I know if i even assign value that is not in enum it will work. Example:
enum example_enum
{
ENUM_VAL0,
ENUM_VAL1,
ENUM_VAL2,
ENUM_VAL3
};
void example_function(void)
{
enum example_enum the_enum = ENUM_VAL3; // correct
the_enum = 41; // will work
the_enum = 0xBADA55; // also will work
bar(the_enum); // this function assumes that input parameter is correct
}
Is there easy, efficient way to check if assignment to enum is correct? I could test value by function
void foo(enum example_enum the_enum)
{
if (!is_enum(the_enum))
return;
// do something with valid enum
}
I could resolve this in following way:
static int e_values[] = { ENUM_VAL0, ENUM_VAL1, ENUM_VAL2, ENUM_VAL3 };
int is_enum(int input)
{
for (int i=0;i<4;i++)
if (e_values[i] == input)
return 1;
return 0;
}
For me, my solution is inefficient, how can i write this if i have more enums and more values in enums?
As long as the enum is continuous one can do something like this:
static int e_values[] = { ENUM_VAL0, ENUM_VAL1, ENUM_VAL2, ENUM_VAL3, ENUM_VAL_COUNT };
int is_enum(int input) { return 0 <= input && input < ENUM_VAL_COUNT; }
Another alternative is to not validate the enum value beforehand, but error out once the code detects an invalid value:
switch(input) {
case ENUM_VAL0: ... break;
case ENUM_VAL1: ... break;
...
default:
assert(0 && "broken enum");
break;
}
But there is no way to enforce that the enum value doesn't go out of the range at all in C. The best you can do if you want to secure the enum against fiddling is to hide the value away in a struct and then have functions to manipulate the struct. The function and struct implementation can be hidden away from the user via a forward declaration in the .h file and the implementation in the .c file:
struct example_t {
enum example_enum value;
}
void example_set_val0(example_t* v) { v->value = ENUM_VAL0; }
There is no way of warning about assigning integers that fit into the enum.
Enumerators in C are synonyms for integer types. Assuming the type chosen for enum example_enum is int, then your code is identical to:
void example_function(void)
{
int the_enum = ENUM_VAL3; // correct
the_enum = 12345; // will work
bar(the_enum); // this function assumes that input parameter is correct
}
void foo(int the_enum)
{
if (!is_enum(the_enum))
return;
// do something with valid enum
}
You could use structures, but even that can be circumvented:
struct example_enum_struct e = { 12345 };
e.value = 23456;
Basically if you want to restrict a type to specific values, you will need to perform checks.
If anyone is interested in this topic, here I have some solution which works.
typed_enums.h
#ifndef TYPED_ENUMS_H
#define TYPED_ENUMS_H
#define TYPED_ENUM(name_) \
typedef struct { int v; } name_
#define TYPED_ENUM_VALUE(name_, value_) (name_) { value_ }
#define GET_TYPED_ENUM_VALUE(en_) (en_.v)
#define TYPED_ENUM_EQ(a_, b_) (GET_TYPED_ENUM_VALUE(a_) == GET_TYPED_ENUM_VALUE(b_))
#endif
usb_class.h
#ifndef USB_CLASS_H
#define USB_CLASS_H
#include "typed_enums.h"
TYPED_ENUM(UsbClass);
#define USB_CLASS_BILLBOARD TYPED_ENUM_VALUE(UsbClass, 0x11)
#define USB_CLASS_TYPE_C_BRIDGE TYPED_ENUM_VALUE(UsbClass, 0x12)
#define USB_CLASS_DIAGNOSTIC_DEVICE TYPED_ENUM_VALUE(UsbClass, 0xDC)
#define USB_CLASS_WIRELESS_CONTROLLER TYPED_ENUM_VALUE(UsbClass, 0xE0)
#endif
usb_class_example.c
#include "typed_enums.h"
#include "usb_class.h"
#include <stdio.h>
int main(int argc, char ** argv)
{
UsbClass usbClass = USB_CLASS_WIRELESS_CONTROLLER;
usbClass = 12345; // tadam!!!! throws error
usbClass = USB_CLASS_VIDEO;
if (TYPED_ENUM_EQ(usbClass, USB_CLASS_VIDEO)) {
printf("usbClass = USB_CLASS_VIDEO\n");
}
printf("usb class value: %02X\n", GET_TYPED_ENUM_VALUE(usbClass));
return 0;
}
Pros:
enum value assignment works like struct assignment
enum for pointers also works
enum value can't be changed
Cons:
can't be used in switch
can't be directly compared
can't directly return enum number value
Note: sorry for abusing preprocessor here
I made this state machine :
enum states { STATE_ENTRY, STATE_....} current_state;
enum events { EVENT_OK, EVENT_FAIL,EVENT_REPEAT, MAX_EVENTS } event;
void (*const state_table [MAX_STATES][MAX_EVENTS]) (void) = {
{ action_entry , action_entry_fail , action_entry_repeat }, /*
procedures for state 1 */
......}
void main (void){
event = get_new_event (); /* get the next event to process */
if (((event >= 0) && (event < MAX_EVENTS))
&& ((current_state >= 0) && (current_state < MAX_STATES))) {
state_table [current_state][event] (); /* call the action procedure */
printf("OK 0");
} else {
/* invalid event/state - handle appropriately */
}
}
When I modify a global variable in one state the global variable remain the same , and I need that variable in all the states . Do you now what could be the problem ?
My Global variable is this structure:
#if (CPU_TYPE == CPU_TYPE_32)
typedef uint32_t word;
#define word_length 32
typedef struct BigNumber {
word words[64];
} BigNumber;
#elif (CPU_TYPE == CPU_TYPE_16)
typedef uint16_t word;
#define word_length 16
typedef struct BigNumber {
word words[128];
} BigNumber;
#else
#error Unsupported CPU_TYPE
#endif
BigNumber number1 , number2;
Here is how I modify:
//iterator is a number from where I start to modify,
//I already modified on the same way up to the iterator
for(i=iterator+1;i<32;i++){
nr_rand1=661;
nr_rand2=1601;
nr_rand3=1873;
number2.words[i]=(nr_rand1<<21) | (nr_rand2<<11) | (nr_rand3);
}
This is just in case you may want to change your approach for defining the FSM. I'll show you with an example; say you have the following FSM:
You may represent it as:
void function process() {
fsm {
fsmSTATE(S) {
/* do your entry actions heare */
event = getevent();
/* do you actions here */
if (event.char == 'a') fsmGOTO(A);
else fsmGOTO(E);
}
fsmSTATE(A) {
event = getevent();
if (event.char == 'b' || event.char == 'B') fsmGOTO(B);
else fsmGOTO(E);
}
fsmSTATE(B) {
event = getevent();
if (event.char == 'a' ) fsmGOTO(A);
else fsmGOTO(E);
}
fsmSTATE(E) {
/* done with the FSM. Bye bye! */
}
}
}
I do claim (but I believe someone will disagree) that this is simpler, much more readable and directly conveys the structure of the FSM than using a table. Even if I didn't put the image, drawing the FSM diagram would be rather easy.
To get this you just have to define the fsmXXX stuff as follows:
#define fsm
#define fsmGOTO(x) goto fsm_state_##x
#define fsmSTATE(x) fsm_state_##x :
Regarding the code that changese number2:
for(i=iterator+1;i<32;i){
nr_rand1=661;
nr_rand2=1601;
nr_rand3=1873;
number2.words[i]=(nr_rand1<<21) | (nr_rand2<<11) | (nr_rand3);
}
I can't fail to note that:
i is never incremented, so just one element of the array is changed (iterator+1) over an infinite loop;
even if i would be incremented, only the a portion of the words array it's changed depending on the value of iterator (but this might be the intended behaviour).
unless iterator can be -1, the element words[0] is never changed (again this could be the intended behaviour).
I would check if this is really what you intended to do.
If you're sure that it's just a visibility problem (since you said that when you declare it as local it worked as expected), the only other thing that I can think of is that you have the functions in one file and the main (or where you do your checks) in another.
Then you include the same .h header in both files and you end up (due to the linker you're using) with two different number2 because you did not declare it as extern in one of the two files.
Your compiler (or, better, the linker) should have (at least) warned you about this, did you check the compilation messages?
This is not an answer - rather it is a comment. But it is too big to fit the comment field so I post it here for now.
The code posted in the question is not sufficient to find the root cause. You need to post a minimal but complete example that shows the problem.
Something like:
#include<stdio.h>
#include<stdlib.h>
#include <stdint.h>
typedef uint32_t word;
#define word_length 32
typedef struct BigNumber {
word words[4];
} BigNumber;
BigNumber number2;
enum states { STATE_0, STATE_1} current_state;
enum events { EVENT_A, EVENT_B } event;
void f1(void)
{
int i;
current_state = STATE_1;
for (i=0; i<4; ++i) number2.words[i] = i;
}
void f2(void)
{
int i;
current_state = STATE_0;
for (i=0; i<4; ++i) number2.words[i] = 42 + i*i;
}
void (*const state_table [2][2]) (void) =
{
{ f1 , f1 },
{ f2 , f2 }
};
int main (void){
current_state = STATE_0;
event = EVENT_A;
state_table [current_state][event] (); /* call the action procedure */
printf("%u %u %u %u\n", number2.words[0], number2.words[1], number2.words[2], number2.words[3]);
event = EVENT_B;
state_table [current_state][event] (); /* call the action procedure */
printf("%u %u %u %u\n", number2.words[0], number2.words[1], number2.words[2], number2.words[3]);
return 0;
}
The above can be considered minimal and complete. Now update this code with a few of your own functions and post that as the question (if it still fails).
My code doesn't fail.
Output:
0 1 2 3
42 43 46 51
I have this enums:
enum bus {
MEDIA_BUS_UNKNOWN,
MEDIA_BUS_VIRTUAL = 1 << 1,
MEDIA_BUS_PCI = 1 << 2,
MEDIA_BUS_USB = 1 << 3,
};
and:
enum bus get_bus( char *sys )
{
FILE *fd;
char file[PATH_MAX];
char s[1024];
if(!strcmp(sys, "/sys/devices/virtual"))
return MEDIA_BUS_VIRTUAL;
snprintf(file, PATH_MAX, "%s/modalias", sys);
fd = fopen(file, "r");
if(!fd)
return MEDIA_BUS_UNKNOWN;
if(!fgets(s, sizeof(s), fd)) {
fclose(fd);
return MEDIA_BUS_UNKNOWN;
}
fclose(fd);
if(!strncmp(s, "pci", 3))
return MEDIA_BUS_PCI;
if(!strncmp(s, "usb", 3))
return MEDIA_BUS_USB;
return MEDIA_BUS_UNKNOWN;
}
I want to create a function to return device(s) with pci or usb bus:
const char *get_device(const enum bus desired_bus)
{
enum bus bus;
...................................................
for( i = 0; i < md->md_size; i++, md_ptr++ ) {
bus = get_bus( md_ptr->sys );
if( ( bus & desired_bus ) == desired_bus )
return md_ptr->node;
}
and call this function to return device(s):
get_device(const enum bus desired_bus)
if request is for devices with pci or usb bus type:
get_device(MEDIA_BUS_PCI | MEDIA_BUS_USB);
It is possible to use math operators for enum?
Sure you can use math operators, but I believe you're looking for bitwise operations, right?. In this case, you enum members values need to be power of two, sou you will be able to do test like this: if(desired_bus & MEDIA_BUS_PCI) if a previously desired_bus |= MEDIA_BUS_PCI was done the if will have MEDIA_BUS_PCI value, so if is true meaning the bit is set.
code example:
enum bus {
MEDIA_BUS_UNKNOWN,
MEDIA_BUS_VIRTUAL = 1 << 1,
MEDIA_BUS_PCI = 1 << 2,
MEDIA_BUS_USB = 1 << 3,
};
/* set flags */
desired_bus |= (MEDIA_BUS_PCI | MEDIA_BUS_USB);
and then:
/* test if flag MEDIA_BUS_PCI was requested.. */
if(desired_bus & MEDIA_BUS_PCI)
In case of it is not set, we get a 0 value that match to our MEDIA_BUS_UNKNOWN value that I think that is a nice to mean error.
EDIT A more complete working C example:
enum bus {
MEDIA_BUS_UNKNOWN,
MEDIA_BUS_VIRTUAL = 1 << 1,
MEDIA_BUS_PCI = 1 << 2,
MEDIA_BUS_USB = 1 << 3,
};
enum bus get_bus( const char *sys );
int main(int argc, char *argv[])
{
const char *sym = argv[1];
enum bus b = get_bus(sym);
if(b & MEDIA_BUS_VIRTUAL)
printf("MEDIA_BUS_VIRTUAL requested\n");
if(b & MEDIA_BUS_USB)
printf("MEDIA_BUS_USB requested\n");
return 0;
}
enum bus get_bus( const char *sys )
{
if(!strcmp("pci", sys))
return MEDIA_BUS_VIRTUAL;
if(!strcmp("usb", sys))
return MEDIA_BUS_USB;
if(!strcmp("pci&usb", sys))
return MEDIA_BUS_VIRTUAL | MEDIA_BUS_USB;
return MEDIA_BUS_UNKNOWN;
}
If you invoke the compiled program with:
a.exe usb: will output:
MEDIA_BUS_USB requested
a.exe "pci&usb" will output:
MEDIA_BUS_VIRTUAL requested
MEDIA_BUS_USB requested
NOTE: You might need to use a type like unsigned instead of enum bus (that highest size is int) to hold a set of enum bus values.
Yes, but for your case, you'll want to make sure that each combination of enum-values is unique, and easily decomposed. To do this, you should make each one a distinct power of two:
enum bus {
MEDIA_BUS_UNKNOWN = 1,
MEDIA_BUS_VIRTUAL = 2,
MEDIA_BUS_PCI = 4,
MEDIA_BUS_USB = 8,
};
(You can then test for a match by writing e.g. desired_bus & MEDIA_BUS_PCI.)
It's a matter of personal taste, but I find using enums to hold bitmasks rather misleading.
I would rather do it with #defines, to be able to define mask combinations easily. For instance:
#define MEDIA_BUS_UNKNOWN 0x00
#define MEDIA_BUS_GPU 0x10
#define MEDIA_BUS_CPU 0x20
#define MEDIA_BUS_VIRTUAL (0x1 | MEDIA_BUS_CPU)
#define MEDIA_BUS_PCI (0x2 | MEDIA_BUS_CPU)
#define MEDIA_BUS_USB (0x3 | MEDIA_BUS_CPU)
#define MEDIA_BUS_AGP (0x4 | MEDIA_BUS_GPU)
#define MEDIA_BUS_PCIE (0x5 | MEDIA_BUS_GPU)
#define MEDIA_BUS_PU_MASK 0x30 // to isolate the PU type
#define MEDIA_BUS_TYPE_MASK 0x0F // to isolate the bus type
typedef int bus_type;
(a rather silly example, but I could not find better without straying too far from the OP's question)
I have a C program with some definitions for error codes. Like this:
#define FILE_NOT_FOUND -2
#define FILE_INVALID -3
#define INTERNAL_ERROR -4
#define ...
#define ...
Is it possible to print the name of the definition by its value? Like this:
PRINT_NAME(-2);
// output
FILE_NOT_FOUND
In short, no. The easiest way to do this would be something like so (PLEASE NOTE: this assumes that you can never have an error assigned to zero/null):
//Should really be wrapping numerical definitions in parentheses.
#define FILE_NOT_FOUND (-2)
#define FILE_INVALID (-3)
#define INTERNAL_ERROR (-4)
typdef struct {
int errorCode;
const char* errorString;
} errorType;
const errorType[] = {
{FILE_NOT_FOUND, "FILE_NOT_FOUND" },
{FILE_INVALID, "FILE_INVALID" },
{INTERNAL_ERROR, "INTERNAL_ERROR" },
{NULL, "NULL" },
};
// Now we just need a function to perform a simple search
int errorIndex(int errorValue) {
int i;
bool found = false;
for(i=0; errorType[i] != NULL; i++) {
if(errorType[i].errorCode == errorValue) {
//Found the correct error index value
found = true;
break;
}
}
if(found) {
printf("Error number: %d (%s) found at index %d",errorType[i].errorCode, errorType[i].errorString, i);
} else {
printf("Invalid error code provided!");
}
if(found) {
return i;
} else {
return -1;
}
}
Enjoy!
Additionally, if you wanted to save on typing even more, you could use a preprocessor macro to make it even neater:
#define NEW_ERROR_TYPE(ERR) {ERR, #ERR}
const errorType[] = {
NEW_ERROR_TYPE(FILE_NOT_FOUND),
NEW_ERROR_TYPE(FILE_INVALID),
NEW_ERROR_TYPE(INTERNAL_ERROR),
NEW_ERROR_TYPE(NULL)
};
Now you only have to type the macro name once, reducing the chance of typos.
You can do something like this.
#include <stdio.h>
#define FILE_NOT_FOUND -2
#define FILE_INVALID -3
#define INTERNAL_ERROR -4
const char* name(int value) {
#define NAME(ERR) case ERR: return #ERR;
switch (value) {
NAME(FILE_NOT_FOUND)
NAME(FILE_INVALID)
NAME(INTERNAL_ERROR)
}
return "unknown";
#undef NAME
}
int main() {
printf("==== %d %s %s\n", FILE_NOT_FOUND, name(FILE_NOT_FOUND), name(-2));
}
No, that's not possible. What would this print?
#define FILE_NOT_FOUND 1
#define UNIT_COST 1
#define EGGS_PER_RATCHET 1
PRINT_NAME(1);
Kinda ...
#define ERROR_CODE_1 "FILE_NOT_FOUND"
#define ERROR_CODE_2 "FILE_FOUND"
#define PRINT_NAME(N) ERROR_CODE_ ## N
or:
static char* error_codes(int err) {
static char name[256][256] = {
};
int base = .... lowest error code;
return name[err - base];
}
#define PRINT_NAME(N) error_code(N)
Why not elect to use an enumeration instead?
enum errors {FILE_NOT_FOUND = -2, FILE_INVALID = -3, INTERNAL_ERROR = -4};
FILE *fp = fopen("file.txt", "r");
if(fp == NULL) {
printf("Error\n");
exit(FILE_NOT_FOUND);
}
Not automatically. The name is losing during compilation, and only the constant number remains in the code.
But you can build something like this:
const char * a[] = {"","","FILE_NOT_FOUND","FILE_INVALID"};
and access it by using the define value absolute value as index.
Use designated initializers of C99 for this, but a bit of care is necessary if your error codes are negative.
First a version for positive values:
#define CODE(C) [C] = #C
static
char const*const codeArray[] = {
CODE(EONE),
CODE(ETWO),
CODE(ETHREE),
};
enum { maxCode = (sizeof codeArray/ sizeof codeArray[0]) };
This allocates an array with the length that you need and with the string pointers at the right positions. Note that duplicate values are allowed by the standard, the last one would be the one that is actually stored in the array.
To print an error code, you'd have to check if the index is smaller than maxCode.
If your error codes are always negative you'd just have to negate the code before printing. But it is probably a good idea to do it the other way round: have the codes to be positive and check a return value for its sign. If it is negative the error code would be the negation of the value.
This is how I do it in C:
< MyDefines.h >
#pragma once
#ifdef DECLARE_DEFINE_NAMES
// Switch-case macro for getting defines names
#define BEGIN_DEFINE_LIST const char* GetDefineName (int key) { switch (key) {
#define MY_DEFINE(name, value) case value: return #name;
#define END_DEFINE_LIST } return "Unknown"; }
#else
// Macros for declaring defines
#define BEGIN_COMMAND_LIST /* nothing */
#define MY_DEFINE(name, value) static const int name = value;
#define END_COMMAND_LIST /* nothing */
#endif
// Declare your defines
BEGIN_DEFINE_LIST
MY_DEFINE(SUCCEEDED, 0)
MY_DEFINE(FAILED, -1)
MY_DEFINE(FILE_NOT_FOUND, -2)
MY_DEFINE(INVALID_FILE, -3)
MY_DEFINE(INTERNAL_ERROR -4)
etc...
END_DEFINE_LIST
< MyDefineInfo.h >
#pragma once
const char* GetDefineName(int key);
< MyDefineInfo.c >
#define DECLARE_DEFINE_NAMES
#include "MyDefines.h"
Now, you can use the declared switch-case macro wherever like this:
< WhereEver.c >
#include "MyDefines.h"
#include "MyDefineInfo.h"
void PrintThings()
{
Print(GetDefineName(SUCCEEDED));
Print(GetDefineName(INTERNAL_ERROR));
Print(GetDefineName(-1);
// etc.
}