I would avoid the use of malloc to initialize a structure and I'm looking for the best practice for the design a C software using an oo-style (where possible).
Only C99, not C++
First question, what is preferable when use a struct like an object? typedef its pointer or not?
These are my test(all works using gcc compiler):
case 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct sItem{
int n;
char* text;
} oItem, *Item;
int main(int argc, char** argv) {
Item i1=(&(oItem){.n=1, .text="A"});
Item i2=(&(oItem){.n=100, .text="ABC"});
printf("%d, %s, %d\n", i1->n, i1->text, sizeof(*i1)); // 1, "A", 8
printf("%d, %s, %d\n", i2->n, i2->text, sizeof(*i2)); // 1, "ABC", 8
return (EXIT_SUCCESS);
}
This works, but i think it should not because text is not initialized to contains strings.
Is this an invalid piece of code?
case 2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct sItem{
int n;
char text[5];
} oItem, *Item;
int main(int argc, char** argv) {
Item i1=(&(oItem){.n=1, .text="A"});
Item i2=(&(oItem){.n=100, .text="ABC"});
printf("%d, %s, %d\n", i1->n, i1->text, sizeof(*i1)); // 1, "A", 12
printf("%d, %s, %d\n", i2->n, i2->text, sizeof(*i2)); // 1, "ABC", 12
return (EXIT_SUCCESS);
}
This works and I think it is correct, is it?
case 3
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Item_new(i, n, s) (&(oItem){0});Item_ctor(i, n, s);
#define Item_neww(i, x, s) (&(oItem){\
.n=x,\
.text=s\
})
typedef struct sItem{
int n;
char text[5];
} oItem, *Item;
void Item_ctor(Item i, int n, char* text){
i->n=n;
strcpy(i->text, text);
}
int main(int argc, char** argv) {
Item i1=Item_new(i1, 10, "ABC");
Item i2=Item_neww(i2, 10, "ABC");
printf("%d, %s, %d\n", i1->n, i1->text, sizeof(*i1)); // 10, "ABC", 12
printf("%d, %s, %d\n", i2->n, i2->text, sizeof(*i2)); // 10, "ABC", 12
return (EXIT_SUCCESS);
}
I think this is very nice, but hides the code, and perhaps might be harmful, what do you think?
I case 3, what is the best choice: macro or constructor function?
Don't do 3, macros that contain unprotected ; make me extremely nervous.
Instead I would replace your "new" and "ctor" by the following
#define Item_new(i, n, s) Item_ctor(&(oItem){0}, n, s)
Item Item_ctor(Item i, int n, char* text){
if (i) {
i->n=n;
strncpy(i->text, text, 4);
}
return i;
}
This doesn't break the expectation of the user for Item_new: a real
function like macro that returns a value.
And the ctor should do the necessary checks and never overwrite the memory, i->text[4] will always be 0. (Better would be to have a symbolic constant instead of 5 and use it also for the strncpy call.)
Case 3 is that I see mostly and would recommend. Wrapping the code in a constructor function is perfectly fine - why hiding code would be a problem? In fact, that's a feature - hide the interface from the implementation. Also, don't use macros for that - this is a way too complicated task for a macro, and nevertheless, macros are often evil.
Approach 1 and 2 are extremely ugly (as it turns out, they are also UB) and unreadable in my opinion. Case 1 is, furthermore, not const correct, either use case 2 instead (well, don't use it either because it invokes undefined behaviour) or declare "text" as const char *.
Related
I have many programs where structs are defined. And each time, I have to create a function to print the members. For example,
typedef struct {
char name[128];
char address[1024];
int zip;
} myStruct;
void printMyStruct(myStruct myPeople) {
printf("%s\n",myPeople.name);
printf("%s\n",myPeople.address);
printf("%d\n",myPeople.zip);
}
int main()
{
myStruct myPeople={"myName" , "10 myStreet", 11111};
printMyStruct(myPeople);
}
I know that reflection is not supported in C. And so, I write these printing functions for each struct I defined.
But, I wonder if it exists any tricks to generate automatically these printing functions. I would understand that I have to modify a little bit these functions. But, if a part of the job is done automatically, it would be great.
(This example is simple, sometimes struct are nested or I have array of structs or some fields are pointers, ...)
You can of-course print structs, but expect a lot of non-readable output:
#include <stdio.h>
#include <ctype.h>
struct example {
int x;
int y;
char c;
};
#define NOT_PRINTABLE "Not Printable"
void print_structure(const char *structure, size_t size) {
for (size_t i = 0; i < size; i++) {
printf("%ld)\t%.2X: %.*s\n", i, structure[i],
(isprint(structure[i]) ? 1 : sizeof(NOT_PRINTABLE) - 1),
(isprint(structure[i]) ? &structure[i] : NOT_PRINTABLE));
}
}
int main(int argc, char **argv) {
struct example a;
a.x = 5;
a.y = 6;
a.c = 'A';
print_structure((char *)&a, sizeof(struct example));
return 0;
}
But the issue is that, it will print the structs as it is represented in memory. So 4 byte (32 bit) integer 1 will be represented with 4 bytes, not the char '1'.
And due to the way pointers work, you cannot make out if a member is a pointer or a non-pointer.
Another issue is that structures have padding to help with alignment, and better/efficent use of memory. So you would see a lot of 0x00 in the middle.
Remember that C is a compiled language.
let's consider to use https://copilot.github.com/. it's great.
this is what i have with copilot
typedef struct {
char name[128];
char address[1024];
int zip;
} myStruct;
//print struct myStruct >> auto generate by codepilot after you type a comment `print struct myStruct`
void printStruct(myStruct *s) {
printf("name: %s\n", s->name);
printf("address: %s\n", s->address);
printf("zip: %d\n", s->zip);
}
Can i compare#definevarible andchar * in strcmp as below.
#include<stdio.h>
#include<string.h>
#define var "hello"
int main()
{
char *p ="hello";
if(strcmp(p,var)==0)
printf("same\n");
else
printf("not same\n");
return 0;
}
Is there any risk comapre #define with char *as above example?
Don't trust us, trust the preprocessor output
File "foo.c"
#include <stdio.h>
#include <string.h>
#define var "hello"
int main(void)
{
char *buf="hello";
if(strcmp(buf,var)==0) // Is this good
printf("same");
return 0;
}
now:
gcc -E foo.c
lots of output because of standard system libraries then...:
# 5 "foo.c"
int main(void)
{
char *buf="hello";
if(strcmp(buf,"hello")==0)
printf("same");
return 0;
}
as you see your define has been safely replaced by the string literal.
When you have a doubt, just apply this method to make sure (more useful when converting to strings or concatenating tokens, there are traps to avoid)
In your case, you could also avoid the macro and use:
static const char *var = "hello";
which guarantees that only 1 occurrence of "hello" is set (saves data memory).
No, there is no risk to comapre #define with char* at all.
#include <stdio.h>
#include <string.h>
#define var "hello"
int main(void)
{
char *buf="hello";
if(strcmp(buf,var)==0) // Is this good
printf("same");
return 0;
}
I need to put 3 strings on an array[3][3].
I tried to do it with pointers, but I only receive a single character.
#include <stdio.h>
int array[3][3]
char thing[5] = "thing";
main()
{
thing = array[0][0];
printf("%s", array[0][0];
}
Try this. With due respect your code absolutely incorrect and need many changes. You need to update your programming skills too.
#include <stdio.h>
#include <string.h>
char array[3][6]={0};
char *thing = "this";
main()
{
strcpy(array[0],thing);
printf("%s\n", array[0]);
}
unsigned int H_SMPTR_LEN = 0;
#ifndef _RSZLEN
#define _RSZLEN(nvalue) H_SMPTR_LEN = nvalue;
#endif
//Smart pointer structure with built-in size
typedef struct SMPTR
{
void *MBLOC;
const unsigned int *length;
unsigned int bloc_size;
} SMPTR;
#ifndef _SMPTR
#define _SMPTR(SMPTR, var_sz, v_num) SMPTR.MBLOC = malloc(var_sz * v_num); SMPTR.bloc_size = v_num * var_sz; _RSZLEN(v_num); SMPTR.length = &H_SMPTR_LEN;
#endif
I wrote this code to experiment with const * to an integer. When I run and implement the code above like so:
#include <stdio.h>
#include <stdlib.h>
#include "cdebug.h"
int main(int argc, char **argv)
{
SMPTR s;
_SMPTR(s, sizeof(char), 50);
fprintf(stdout, "%i\n", s.bloc_size);
fprintf(stdout, "%i\n", s.length);
fprintf(stdout, "%i\n", H_SMPTR_LEN);
fprintf(stdout, "%s", "Done!\n");
return 0;
}
The second output statement is a screwy output result. In theory the second output result should match the third, because the SMPTR.length member points to H_SMPTR_LEN.
The first bit of code is part of my header called "cdebug.h", which is included in main(). I am wondering if I am using const pointers correctly here. The idea here is to create a structure whose members can only be modified in a controlled environment, i.e. a method I write.
Hi All,
from the above image.
I am able to compile, but the program crashes at runtime.
Please advise me what could be the resolution to solve this?
Thank you
// structArray.h:
#ifndef __STRUCTARRAY_H_
#define __STRUCTARRAY_H_
typedef struct _vector{
int* str;
int maskSize;
// etc...
}__attribute__((__packed__)) _vector_t;
#endif /* _STRUCTARRAY_H_ */
**// do_structArray.c**
#include "structArray.h"
extern struct _vector_t t;
void do_structArray (void) {
int plaintext[2] = {0x05, 0x08};
_vector_t t[] = {
{plaintext, sizeof(plaintext)},
//{},
};
printf("Content: \n%x \n", t[1].str[1]);
}
// main : just calling do_structArray
#include <stdio.h>
#include <stdlib.h>
#include "structArray.h"
extern struct _vector_t t;
int main(int argc, char *argv[]) {
do_structArray();
system("PAUSE");
return 0;
}
You are accessing t[1] but only have one item in t. Try printf("Content: \n%x \n", t[0].str[1]).
Array indices begin from 0 in C. You're accessing an array element past the end of the array. Change the index to 0:
printf("Content: \n%x \n", t[0].str[0]);