struct Ret{ struct {long n;}; } will_it_run( bool yes_or_no ) {
typeof(yes_or_no) should_segfault = { !yes_or_no };
constexpr int SZ = {6};
double array[SZ] = {
[4]=-1.21570011103803167e-262, 4.94065645841246544e-323,
[0]= 2.85312613025819859e-153, 3.98568242114839056e+252,
5.20628304629909446e+58, 5.81238365411700493e+180
};
auto num = puts( (void *)(array) );
auto ptr = &(struct Ret){ .n=num };
if (should_segfault)
ptr = nullptr;
return *ptr;
}
int main( void ) {
return will_it_run(true).n;
}
C is a razor-sharp tool, with which one can create an elegant and efficient program or a bloody mess.
Brian Kernighan in The Practice of Programming
struct data_t arr[SZ];
memset(arr, 0, sizeof(struct data_t) * SZ);
arr[0].desc = strdup("reserved");
data_t * array_init(data_t * arr, size_t n){
for (size_t i = 0; i < n; i++){
double *p = malloc(sizeof(*p) * SZ * SZ);
arr[i].tensor = p;
}
/* ~~~ */
}
void zero(struct data_t * data ){
data->desc = "maybe zeroed?";
}
data_t * init(data_t ** data){
*data = malloc(sizeof(**data));
if (!(*data)) return 0;
(*data)->tensor = malloc(sizeof(double) * SZ * SZ);
if (!(*data)->tensor){
free(*data);
return 0;
}
return *data;
}
struct rectangle rect = mk_rect();
struct circle circle = mk_circle();
render(&rect);
render(&circle);
How many arguments does print accept?
void print( );
What is the output of the following program?
void print_sum(a, b){
printf("%d", a + b);
}
int main(void){
print_sum(1.5, 8.5);
}
What's the type and value of number?
void func(void){
auto number = 42.24f;
}
Will this compile in C?
void func(void){
bool enable = false;
}
What is the size of the numbers array?
double numbers[] = {0, [10]=55, 89, [5]=5, 8, [1]=1, 1, 2};
How many bytes are allocated by malloc ?
// sizeof(int) == 4
// sizeof(int*) == 8
size_t sz = 10;
int (*pK)[sz][sz] = malloc(sizeof(*pK));
Is this program well-formed?
#include <stdio.h>
#include <time.h>
int main( void ){
struct tm * today = &(struct tm){
.tm_year=123,
.tm_mon=3,
.tm_mday=20
};
mktime(today);
auto buffer = (char [42]){};
strftime(buffer, 42, "%A, %F", today);
puts(buffer);
}
What kind of arguments does accept accept?
void accept(char const str[static 1]);
int no_args( void ){
return 42;
}
int auto_vars( int n ){
auto int squared = n * n;
auto min_one = squared - 1;
return min_one;
}
void func(void){
double* arr = malloc(sizeof(double[N]));
}
#include <stdbool.h>
int get_num( _Bool random ){
return random? rand() : 42;
}
bool random = false;
int num = get_num(random);
const int N = 10;
int arr[N]; // ERROR, not allowed
#define N (10)
int arr[N]; // perfectly fine
union dbl_bytes{
double number;
unsigned char bytes[sizeof(double)];
};
int main(void){
union dbl_bytes db = {42.0};
for (size_t i=0; i < sizeof(db.bytes); ++i)
printf("0x%02x ", db.bytes[i]);
}
C | C++ | |
---|---|---|
sizeof(int) | 4 | 4 |
sizeof(42) | 4 | 4 |
sizeof(char) | 1 | 1 |
sizeof('B') | 4 | 1 |
typedef struct point {
int x;
int y;
} point_s;
point_s makepoint(int x, int y) {
point_s temp;
temp.x = x;
temp.y = y;
return temp;
}
point_s p = makepoint(42, 24);
Do you ever write code like this?
typedef struct point {
int x;
int y;
} point_S;
point_s makepoint(int x, int y) {
point_s temp;
temp.x = x;
temp.y = y;
return temp;
}
point_s p = makepoint(42, 24);
typedef struct point {
int x;
int y;
} point_s;
point_s makepoint(int x, int y) {
point_s tmp = {x, y};
return tmp;
}
point_s p = makepoint(42, 24);
struct data {
const char* str;
int value;
};
// array contains two elements
int array[] = {42, 24};
// numbers contains 10 elements, the first three are: 2, 3, 5
double numbers[10] = {2, 3, 5};
// my_data.str == "alice"
// my_data.value = 123
struct data my_data = {"alice", 123};
Really of any type:
double pi = { 3.1415927 };
Type name = { 0 };
It works for scalars, arrays, structs and unions
struct data {
const char* str;
int value;
};
double value = { 0 };
double numbers[42] = { 0 };
struct data my_data = { 0 };
Type name = { };
It works for scalars, arrays, structs and unions
struct data {
const char* str;
int value;
};
double value = { };
double numbers[42] = { };
struct data my_data = { };
For scalars it just initializes a variable with 0
double value = { 0 }; // value == 0
void *ptr = { 0 }; // ptr == NULL
const char* str = { 0 }; // str == ""
Empty-initialization == zeroing
struct data {
const char* str;
int value;
};
struct data my_data = { 0 };
/*
* my_data.str == ""
* my_data.value == 0
*/
This works also for nested types
struct data {
const char* str;
int value;
};
struct data my_data_array[42] = { 0 };
/*
* my_data_array[0..41].str == ""
* my_data_array.value[0..41] == 0
*/
typedef struct driver {
const char* name;
unsigned char data[16];
uint16_t flags;
uint16_t flags_ex;
status_f status;
} driver_s;
In 95% of cases the data, flags and flags_ex fields are zeroed.
But:
drivers_s my_serial = {"serial", {0}, 0, 0, &status_serial};
typedef struct driver {
const char* name;
unsigned char data[16];
uint16_t flags;
uint16_t flags_ex;
status_f status;
} driver_s;
In 95% of cases the data, flags and flags_ex fields are zeroed.
But:
drivers_s my_serial = {"serial", {0}, 0, 0, &status_serial};
A designated initializer
{ .field_name = value }
To initialize only the name and status fields:
typedef struct driver {
const char* name;
unsigned char data[16];
uint16_t flags;
uint16_t flags_ex;
status_f status;
} driver_s;
driver_s my_serial = {.name="serial", .status=&status_serial};
All the remaining fields are empty-initialized
typedef struct driver {
const char* name;
unsigned char data[16];
uint16_t flags;
uint16_t flags_ex;
status_f status;
} driver_s;
driver_s my_serial = {.status=&status_serial, .name="serial"};
driver_s my_serial = {.name="serial", .status=&status_serial};
typedef struct driver {
const char* name;
unsigned char data[16];
uint16_t flags;
uint16_t flags_ex;
status_f status;
} driver_s;
driver_s my_serial = {"serial", .status=&status_serial};
typedef struct driver {
const char* name;
unsigned char data[16];
uint16_t flags;
uint16_t flags_ex;
status_f status;
} driver_s;
driver_s my_serial = {"serial", .status=&status_serial, .flags=0x1234, 0x4321};
typedef struct flags {
uint16_t standard;
uint16_t extended;
} flags_s;
typedef struct driver {
const char* name;
unsigned char data[16];
flags_s flags;
status_f status;
} driver_s;
driver_s my_serial = {
"serial",
.status= &status_serial,
.flags= { 0x1234, 0x4321 }
};
driver_s my_serial = {
"serial",
.status= &status_serial,
.flags={ .extended=0x4321 }
};
driver_s my_serial = {
"serial",
.status= &status_serial,
.flags.extended = 0x4321
};
double numbers[42] = { [1]=1, [5]=5, [10]=55};
As with structs, items not initialized directly are empty-initialized
double numbers[42] = { [1]=1, [5]=5, [10]=55};
double numbers[42] = { [10]=55, [5]=5, [1]=1 };
double numbers[42] = { [5]=5, [10]=55, [1]=1 };
And positional and designated initializers can be freely mixed
double numbers[42] = {0, [10]=55, 89, [5]=5, 8, [1]=1, 1, 2};
double numbers[] = {0, [10]=55, 89, [5]=5, 8, [1]=1, 1, 2};
numbers has type double[12]
#define SZ (42)
typedef struct data_s {
char * id;
double * values;
} data_s;
data_s arr[SZ] = { [SZ-1].id = "last data point" };
What | C | C++ |
---|---|---|
|
✔ | ✘nope, out of order |
|
✔ | ✘nope, mixed |
|
✔ | ✘nope, nesting |
|
✔ | ✘nope: no array designated initializers |
#define A_LOT (100)
int numbers[A_LOT] = { 0 };
size_t a_lot = { 100 };
int* numbers = malloc(a_lot *
sizeof(int));
#define A_LOT (100)
void func(){
int numbers[A_LOT];
}
constexpr size_t A_LOT = { 100 };
void func(){
int numbers[A_LOT];
}
#define A_LOT (100)
void func(){
int numbers[A_LOT];
}
void func(){
constexpr size_t A_LOT = { 100 };
int numbers[A_LOT];
}
static const size_t A_LOT = { 100 };
void func(){
int numbers[A_LOT];
}
A: No
So why does this code compile?
void filter(size_t len){
// ok - block scope
double buffer[len];
}
size_t size = 100;
// nope - file scope
double oh_no[size];
void filter(size_t len){
double buffer[len];
for (size_t i = 0; i < len; ++i)
buffer[i] = arr[i];
}
USING VLA'S IS ACTIVELY STUPID! It generates much more code,and much slower code (and more fragile code), than just using a fixed (array) size would have done.
Linus Torvalds, 7 March 2018
int test_vla(size_t n){
if (n > MY_ALLOWED_SIZE){
fprintf(stderr, "Too big!");
return -1;
}
int arr[n];
get_data(n, arr);
return sum(n, arr);
}
int test_known_size(size_t n){
if (n > MY_ALLOWED_SIZE){
fprintf(stderr, "Too big!");
return -1;
}
int arr[MY_ALLOWED_SIZE];
get_data(n, arr);
return sum(n, arr);
}
int test_vla(size_t n){
int arr[n];
get_data(n, arr);
return sum(n, arr);
}
int test_known_size(size_t n){
int arr[10];
get_data(n, arr);
return sum(n, arr);
}
test_vla:
push rbp
mov rbp, rsp
push r14
push rbx
mov rbx, rdi
mov r14, rsp
lea rax, [4*rdi + 15]
and rax, -16
sub r14, rax
mov rsp, r14
mov rsi, r14
; get_data & sum calls
lea rsp, [rbp - 16]
pop rbx
pop r14
pop rbp
ret
test_known_size:
push r14
push rbx
sub rsp, 40
mov rbx, rdi
mov r14, rsp
mov rsi, r14
; get_data & sum calls
add rsp, 40
pop rbx
pop rbp
ret
int test_known_size(size_t n){
int arr[10];
get_data(n, arr);
return sum(n, arr);
}
int test_vla(size_t n){
int arr[n];
get_data(n, arr);
return sum(n, arr);
}
void get_data(size_t n, int *arr){
for (size_t i = 0; i < n; ++i)
arr[i] = (i+1) * (i+1);
}
int main_a(void){
int n = 10;
return test_known_size(n);
}
int main_b(void){
int n = 10;
return test_vla(n);
}
main_a:
mov eax, 385
ret
main_b:
mov eax, 385
ret
int use_vla(size_t n, int * numbers){
return numbers[n/2];
}
int use_vla(size_t n, int numbers[n]){
return numbers[n/2];
}
The variable length argument (size_t n) must come before the VLA
int use_vla(size_t n, int numbers[n]){
return numbers[n/2];
}
int main(void){
int numbers[] = {1, 2, 3, 4, 5};
return use_vla(5, numbers);
}
[GCC 12] warning: 'use_vla' accessing 24 bytes in a region of size 20 [-Wstringop-overflow=]
int use_vla(size_t n, int numbers[n]){
return numbers[n/2];
}
int main(void){
int numbers[] = {1, 2, 3, 4, 5};
return use_vla(6, numbers);
}
[GCC 12] warning: 'use_vla' accessing 24 bytes in a region of size 20 [-Wstringop-overflow=]
int use_vla(size_t n, int numbers[n]){
return numbers[n/2];
}
int main(void){
int* pnumbers = malloc(sizeof(int[5]));
// init pnumbers
return use_vla(6, pnumbers);
}
[GCC 12] warning: 'use_vla' accessing 24 bytes in a region of size 20 [-Wstringop-overflow=]
void make_great( int n, char buffer[n] ){
const char * str = "C is great, long live C!";
while (--n > 0 && *str){
*buffer++ = *str++;
}
*buffer = '\0';
}
void sum( size_t n, double numbers[static n] ){
double sum = 0;
for(size_t i = 0; i < n; ++i ){
sum += numbers[i];
}
return sum;
}
time_t time( time_t * arg ){
time_t result = /* ??? */ ;
if (arg)
*arg = result;
return result;
}
size_t strlen(const char str[static 1]){
size_t len = 0;
while( *str++ != '\0')
++len;
return len;
}
constexpr size_t N = {42};
void func( Type array[static N] );
void func( size_t n, Type array[static n] );
pair_s solve_quadratic(double coeffs[static 3]);
double c0[] = {1, 2};
double* c1 = malloc(sizeof(double[2]));
pair_s r = solve_quadratic(c0);
pair_s r = solve_quadratic(c1);
size_t strlen(const char str[static 1]);
const char* str = nullptr;
size_t len = strlen(str);
What | How | Result |
---|---|---|
A single object,
can be null
|
|
func is responsible for checking obj |
A single object,
must exist/ shouldn't be null
|
|
Compilers might emit a warning
|
Multiple objects,
possibly invalid/ non-existing
|
|
Compilers might emit a warning
|
Multiple objects,
must exist/ shouldn't be NULL
|
|
Compilers might emit a warning
|
double* kernel_gauss_create(size_t sz){
double *pK = malloc(sizeof(double[sz][sz]));
// ...
return pK;
}
double* kernel_gauss_create(size_t sz){
double *pK = malloc(sizeof(double[sz*sz]));
if (!pK) return pK;
for (size_t i=0; i < sz; ++i)
for (size_t j=0; j < sz; ++j)
*(pK + i*sizeof(double[sz]) + j) = _gcoeff(sz, i, j);
return pK;
}
*(pK + i*sizeof(double[sz]) + j) = _gcoeff(sz, i, j);
We mean:
pK[i][j] = _gcoeff(sz, i, j);
double* kernel_gauss_create(size_t sz){
double (*pK)[sz][sz] = malloc(sizeof(*pK));
if (!pK) return NULL;
for (size_t i=0; i < sz; ++i)
for (size_t j=0; j < sz; ++j)
(*pK)[i][j] = _gcoeff(sz, i, j);
return (double *)pK;
}
double* kernel_gauss_create(size_t sz){
double (*pK)[sz] = malloc(sizeof(*pK) * sz);
if (!pK) return NULL;
for (size_t i=0; i < sz; ++i)
for (size_t j=0; j < sz; ++j)
pK[i][j] = _gcoeff(sz, i, j);
return (double *)pK;
}
double* kernel_gauss_create(size_t sz){
double (*pK)[sz] = malloc(sizeof( typeof(*pK)[sz] ));
if (!pK) return nullptr;
for (size_t i=0; i < sz; ++i)
for (size_t j=0; j < sz; ++j)
pK[i][j] = _gcoeff(sz, i, j);
return (double *)pK;
}
typedef struct point {
int x;
int y;
} point_S;
point_s makepoint(int x, int y) {
point_s temp;
temp.x = x;
temp.y = y;
return temp;
}
point_s p = makepoint(42, 24);
typedef struct point {
int x;
int y;
} point_s;
point_s makepoint(int x, int y) {
point_s tmp = {.x=x, .y=y};
return tmp;
}
point_s p = makepoint(42, 24);
typedef struct point {
int x;
int y;
} point_S;
point_s makepoint(int x, int y) {
point_s temp;
temp.x = x;
temp.y = y;
return temp;
}
point_s p = makepoint(42, 24);
typedef struct point {
int x;
int y;
} point_s;
point_s makepoint(int x, int y) {
return (point_s) {.x=x, .y=y};
}
point_s p = makepoint(42, 24);
This is known as compound literals
(Type){ /* initializer list */ }
Creates an unnamed object of type Type
static const double* default_coeffs = (double[]){0.12, 0.32, 0.32, 0.12};
void filter(...){}
typedef struct fir4{
const double* coeffs;
double buffer[4];
} fir4_s;
void filter(size_t n, double arr[n]){
fir4_s fir = { ... };
// ...
fir = (fir4_s){.coeffs=default_coeffs, .buffer={0}};
// ...
}
static const double* default_coeffs =
(double[]){0.12, 0.32, 0.32, 0.12};
void filter(size_t n, double arr[n]){
size_t len = n * 2;
fir4_s fir = { ... };
// ...
fir = (fir4_s){.coeffs=default_coeffs,
.buffer={0}};
// ...
}
Type* ptr = &(Type){ /* initializer list */}
time_t time = mktime( &(struct tm){ .tm_year=2021, .tm_mon=6, .tm_mday=1, .tm_isdst=-1 } );
Compound literals are not supported in ISO C++
They are not C++ temporaries
time_t time = mktime( &(struct tm){
.tm_year=2021,
.tm_mon=6,
.tm_mday=1,
.tm_isdst=-1 }
);
Valid C - taking an addressof a compound literal
std::time_t time = std::mktime( &std::tm{
.tm_mday=1,
.tm_mon=6,
.tm_year=2021,
.tm_isdst=-1 }
);
Invalid C++ - taking an addressof an rvalue (temporary)
typedef struct array {
double* data;
size_t capacity;
size_t count;
} array_s;
array_s* array_init(array_s * pa, size_t capacity);
array_s* array_init(array_s * pa, size_t capacity){
memset(pa, 0, sizeof(*pa));
pa->data = calloc(capacity, sizeof(*pa->data));
if (pa->data)
pa->capacity = capacity;
return pa;
}
Compound literal + designated initializers
(pa->count and pa->capacity are zeroed automatically)
array_s* array_init(array_s * pa, size_t capacity){
*pa = (array_s){
.data = calloc(capacity, sizeof(*pa->data))
};
if (pa->data)
pa->capacity = capacity;
return pa;
}
Compound literal + designated initializers
(pa->count and pa->capacity are zeroed automatically)
array_s* array_init(array_s pa[static 1], size_t capacity){
*pa = (array_s){
.data = calloc(capacity, sizeof(*pa->data))
};
if (pa->data)
pa->capacity = capacity;
return pa;
}
Compound literal + designated initializers
(pa->count and pa->capacity are zeroed automatically)
void array_free(array_s * pa){
if (pa && pa->data){
free(pa->data);
}
memset(pa, 0, sizeof(*pa));
return pa;
}
Compound literal + designated initializers
All the *pa's data is zeroed.Compilers will call memset for you.
void array_free(array_s pa[static 1]){
if (pa && pa->data){
free(pa->data);
}
*pa = (array_s){ 0 };
return pa;
}
Compound literal + empty initialization
All the *pa's data is zeroed.Compilers will call memset for you.
image_s* blur(image_s * img, size_t width, blur_type type, int cwh, _Bool in_place);
typedef struct blur_params {
size_t width;
blur_type type;
int compute_hw;
_Bool in_place;
} blur_params_s;
image_s* blur(image_s img[static 1], blur_params_s params[static 1]);
blur_params_s params = { .width=64, .type=box, .compute_hw=0, .in_place=true };
blur(&img, ¶ms);
image_s* blur(image_s img[static 1], blur_params_s params[static 1]);
blur(&img, &(blur_params_s){ .width=64, .type=box, .compute_hw=0, .in_place=true });
image_s* blur(image_s img[static 1], blur_params_s params[static 1]);
blur(&img, &(blur_params_s){ .width=64, .type=box, .compute_hw=0, .in_place=true });
blur(&img, &(blur_params_s){ .width=64, .in_place=true });
blur( &img, .width=64, .in_place=true );
image_s* blur_(image_s img[static 1], blur_params_s params[static 1]);
#define blur(img, ...) blur_((img), &(blur_params_s){__VA_ARGS__})
image_s* blur_(image_s img[static 1], blur_params_s params[static 1]);
#define blur(img, ...) blur_((img), &(blur_params_s){__VA_ARGS__})
blur( &img, .width=64, .in_place=true );
enum blur_type{ box, gauss };
image_s* blur_(image_s img[static 1], blur_params_s params[static 1]);
#define blur(img, ...) \
blur_((img), &(blur_params_s){.width=32, .type=gauss, __VA_ARGS__})
blur( &img, .width=64, .in_place=true );
image_s* _blur(image_s img[static 1], blur_params_s params[static 1]);
#define DEF_ARGS_ON \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Woverride-init\"")
#define DEF_ARGS_OFF \
_Pragma("GCC diagnostic pop")
#define blur(img, ...) \
DEF_ARGS_ON \
_blur((img), (blur_params_s){.width=64, .type=gauss, __VA_ARGS__}) \
DEF_ARGS_OFF
blur( &img, .width=64, .in_place=true );
typedef struct string{
size_t sz_arr;
size_t length;
char* arr;
} string_s;
// sizeof(string_s) == 24
string_s* mk_string(const char str[static 1]){
string_s* p = malloc(sizeof(*p));
if (p){
size_t len = strlen(str);
*p = (string_s){
.sz_arr = len + 1,
.length = len,
.arr = malloc(len + 1)
};
if (p->arr){
memcpy(p->arr, str, len +1);
}
else{
free(p);
p = NULL;
}
}
return p;
}
typedef struct string{
size_t sz_arr;
size_t length;
char * arr;
} string_s;
// sizeof(string_s) == 24
typedef struct string{
size_t sz_arr;
size_t length;
char arr[];
} string_s;
// sizeof(string_s) == 16
typedef struct string{
size_t sz_arr;
size_t length;
char arr[];
} string_s;
#define ARR_SZ (100)
string_s names[ARR_SZ];
struct person{
string_s name;
int id;
};
✘ cannot be a member of another struct
string_s str = {
.sz_arr = 0,
.length = 0,
.arr = "alice"};
✘ direct initialization of the flexible array member
string_s* mk_string(const char str[static 1]){
size_t len = strlen(str);
string_s* p = malloc(sizeof(*p) +
sizeof(char[len + 1]));
if (p){
*p = (string_s){.sz_arr = len + 1,
.length = len};
memcpy(p->arr, str, len + 1);
}
return p;
}
typedef struct Point2D {
double x, y;
} Point2D_s;
typedef struct Circle {
Point2D_s center;
double radius;
} Circle_s;
typedef struct Rectangle {
Point2D_s center;
double w, h;
} Rectangle_s;
void scale(Circle_s c[static 1], double scale){
c->radius *= scale;
}
void scale(Rectangle_s r[static 1], double scale){
r->w *= scale;
r->h *= scale;
}
void scale_circ(Circle_s c[static 1], double scale){
c->radius *= scale;
}
void scale_rect(Rectangle_s r[static 1], double scale){
r->w *= scale;
r->h *= scale;
}
void scale_circ(Circle_s c[static 1], double scale);
void scale_rect(Rectangle_s r[static 1], double scale);
#define scale(obj, scale) \
_Generic( (obj), \
Rectangle_s* : scale_rect, \
Circle_s* : scale_circ \
) \
((obj), (scale))
void func(){
Rectangle rect;
Circle circ;
scale(&rect, 5.3);
scale(&circ, 3.5);
}
void scale_circ_1p(Circle_s c[static 1], double scale);
void scale_rect_1p(Rectangle_s r[static 1], double scale);
void scale_rect_2p(Rectangle_s r[static 1], double w_scale, double h_scale);
void func(){
Rectangle rect1;
Rectangle rect2;
scale(&rect1, 5.3);
scale(&rect2, 5.3, 3.5)
}
#define scale2p(obj, ...) \
_Generic( (obj), \
Rectangle_s* : scale_rect_2p \
)((obj), __VA_ARGS__)
#define scale1p(obj, ...) \
_Generic( (obj), \
Rectangle_s* : scale_rect_1p, \
Circle_s* : scale_circ_1p \
)((obj), __VA_ARGS__)
they are passed on with __VA_ARGS__
#define scale2p(obj, ...) \
_Generic( (obj), \
Rectangle_s* : scale_rect_2p \
)((obj), __VA_ARGS__)
#define scale1p(obj, ...) \
_Generic( (obj), \
Rectangle_s* : scale_rect_1p, \
Circle_s* : scale_circ_1p \
)((obj), __VA_ARGS__)
#define INVOKE(_1, _2, _3, NAME, ...) NAME
#define scale(...) INVOKE(__VA_ARGS__, scale2p, scale1p,)(__VA_ARGS__)
typedef struct vector {
size_t capacity;
size_t size;
Type * data;
} vector;
int vec_create(vector ** vec, size_t cap){
if (*vec != NULL)
return -1;
*vec = (vector *)malloc(sizeof(**vec));
if (*vec == NULL)
return -1;
cap = cap == 0? DEF_CAP : cap;
(*vec)->data = (Type *)malloc(cap * sizeof(Type));
if ((*vec)->data == NULL){
free(*vec);
*vec = NULL;
return -1;
}
(*vec)->capacity = cap;
(*vec)->size = 0;
return 1;
}
vector * vec = NULL;
if (vec_create(&vec, 8) >= 0){
/* do something */
}
vector * vec = {};
if (vec_create(&vec, 8)){
/* do something */
}
typedef struct vector {
size_t capacity;
size_t size;
Type * data;
} vector;
int vec_create(vector ** vec, size_t cap){
if (*vec != NULL)
return -1;
*vec = (vector *)malloc(sizeof(**vec));
if (*vec == NULL)
return -1;
cap = cap == 0? DEF_CAP : cap;
(*vec)->data = (Type *)malloc(cap * sizeof(Type));
if ((*vec)->data == NULL){
free(*vec);
*vec = NULL;
return -1;
}
(*vec)->capacity = cap;
(*vec)->size = 0;
return 1;
}
typedef struct vector {
size_t capacity;
size_t size;
Type * data;
} vector;
bool vec_create(vector ** vec, size_t cap){
if (*vec != NULL)
return false;
*vec = (vector *)malloc(sizeof(**vec));
if (*vec == NULL)
return false;
cap = cap == 0? DEF_CAP : cap;
(*vec)->data = (Type *)malloc(cap * sizeof(Type));
if ((*vec)->data == NULL){
free(*vec);
*vec = NULL;
return false;
}
(*vec)->capacity = cap;
(*vec)->size = 0;
return true;
}
typedef struct vector {
size_t capacity;
size_t size;
Type * data;
} vector;
bool vec_create(vector * vec[static 1], size_t cap){
if (*vec != NULL)
return false;
*vec = (vector *)malloc(sizeof(**vec));
if (*vec == NULL)
return false;
cap = cap == 0? DEF_CAP : cap;
(*vec)->data = (Type *)malloc(cap * sizeof(Type));
if ((*vec)->data == NULL){
free(*vec);
*vec = NULL;
return false;
}
(*vec)->capacity = cap;
(*vec)->size = 0;
return true;
}
typedef struct vector {
size_t capacity;
size_t size;
Type * data;
} vector;
bool vec_create(vector * vec[static 1], size_t cap){
if (*vec != nullptr)
return false;
*vec = (vector *)malloc(sizeof(**vec));
if (*vec == nullptr)
return false;
cap = cap == 0? DEF_CAP : cap;
(*vec)->data = (Type *)malloc(cap * sizeof(Type));
if ((*vec)->data == nullptr){
free(*vec);
*vec = nullptr;
return false;
}
(*vec)->capacity = cap;
(*vec)->size = 0;
return true;
}
typedef struct vector {
size_t capacity;
size_t size;
Type * data;
} vector;
bool vec_create(vector * vec[static 1], size_t cap){
if (*vec != nullptr)
return false;
*vec = (vector *)malloc(sizeof(**vec));
if (*vec == nullptr)
return false;
cap = cap == 0? DEF_CAP : cap;
**vec = (vector){ .data = malloc(cap * sizeof(Type)),
.capacity = cap};
if ((*vec)->data == nullptr){
free(*vec);
*vec = nullptr;
return false;
}
return true;
}
typedef struct vector {
size_t capacity;
size_t size;
Type * data;
} vector;
bool vec_create(vector * vec[static 1], size_t cap){
if (*vec != nullptr)
return false;
*vec = (vector *)malloc(sizeof(**vec));
if (*vec == nullptr)
return false;
cap = cap == 0? DEF_CAP : cap;
**vec = (vector){ .data = malloc(sizeof(Type[cap])),
.capacity = cap};
if ((*vec)->data == nullptr){
free(*vec);
*vec = nullptr;
return false;
}
return true;
}
typedef struct vector {
size_t capacity;
size_t size;
Type * data;
} vector;
bool vec_create(vector * vec[static 1], size_t cap){
if (*vec != nullptr)
return false;
*vec = (vector *)malloc(sizeof(**vec));
if (*vec == nullptr)
return false;
constexpr size_t DEF_CAP = 16;
cap = cap == 0? DEF_CAP : cap;
**vec = (vector){ .data = malloc(sizeof(Type[cap])),
.capacity = cap};
if ((*vec)->data == nullptr){
free(*vec);
*vec = nullptr;
return false;
}
return true;
}
typedef struct vector {
size_t capacity;
size_t size;
Type * data;
} vector;
bool vec_create(vector * vec[static 1], size_t cap){
if (*vec != nullptr)
return false;
*vec = (vector *)malloc(sizeof(**vec));
if (*vec == nullptr)
return false;
constexpr size_t DEF_CAP = 16;
cap = cap == 0? DEF_CAP : cap;
**vec = (vector){ .data = malloc(sizeof(Type[cap])),
.capacity = cap};
if ((*vec)->data == nullptr){
free(*vec);
*vec = nullptr;
return false;
}
return true;
}
typedef struct vector {
size_t capacity;
size_t size;
Type data[];
} vector;
bool vec_create(vector * vec[static 1], size_t cap){
if (*vec != nullptr)
return false;
*vec = (vector *)malloc(sizeof(**vec));
if (*vec == nullptr)
return false;
constexpr size_t DEF_CAP = 16;
cap = cap == 0? DEF_CAP : cap;
**vec = (vector){ .data = malloc(sizeof(Type[cap])),
.capacity = cap};
if ((*vec)->data == nullptr){
free(*vec);
*vec = nullptr;
return false;
}
return true;
}
typedef struct vector {
size_t capacity;
size_t size;
Type data[];
} vector;
bool vec_create(vector * vec[static 1], size_t cap){
if (*vec != nullptr)
return false;
constexpr size_t DEF_CAP = 16;
cap = cap == 0? DEF_CAP : cap;
*vec = malloc(sizeof(**vec) + sizeof(Type[cap]));
if (*vec != nullptr){
**vec = (vector){ .capacity = cap };
}
return true;
}
typedef struct vector {
size_t capacity;
size_t size;
Type data[];
} vector;
bool vec_create(vector * vec[static 1], size_t cap){
if (*vec != nullptr)
return false;
constexpr size_t DEF_CAP = 16;
cap = cap == 0? DEF_CAP : cap;
*vec = malloc(sizeof(**vec) + sizeof(Type[cap]));
if (*vec != nullptr){
**vec = (vector){ .capacity = cap };
}
return *vec != nullptr;
}
typedef struct vector {
size_t capacity;
size_t size;
Type data[];
} vector;
bool vec_create(vector * vec[static 1], size_t cap){
if (*vec != nullptr)
return false;
constexpr size_t DEF_CAP = 16;
cap = cap == 0? DEF_CAP : cap;
*vec = malloc(sizeof(**vec) +
sizeof(Type[cap]));
if (*vec != nullptr){
**vec = (vector){ .capacity = cap };
}
return *vec != nullptr;
}
typedef struct vector {
size_t capacity;
size_t size;
Type data[];
} vector;
bool vec_create(vector * vec[static 1], size_t cap){
if (*vec != nullptr)
return false;
constexpr size_t DEF_CAP = 16;
cap = cap == 0? DEF_CAP : cap;
*vec = malloc(sizeof(**vec) +
sizeof(typeof(*(*vec)->data)[cap]))
if (*vec != nullptr){
**vec = (vector){ .capacity = cap };
}
return *vec != nullptr;
}
typedef struct vector {
size_t capacity;
size_t size;
Type data[];
} vector;
typedef struct vc_args { size_t cap; } vc_args;
bool vec_create(vector * vec[static 1], vc_args args){
if (*vec != nullptr)
return false;
constexpr size_t DEF_CAP = 16;
cap = cap == 0? DEF_CAP : cap;
*vec = malloc(sizeof(**vec) +
sizeof(typeof(*(*vec)->data)[args.cap]))
if (*vec != nullptr){
**vec = (vector){ .capacity = args.cap };
}
return *vec != nullptr;
}
typedef struct vector {
size_t capacity;
size_t size;
Type data[];
} vector;
typedef struct vc_args { size_t cap; } vc_args;
bool vec_create(vector * vec[static 1], vc_args args){
if (*vec != nullptr)
return false;
constexpr size_t DEF_CAP = 16;
cap = cap == 0? DEF_CAP : cap;
*vec = malloc(sizeof(**vec) +
sizeof(typeof(*(*vec)->data)[args.cap]))
if (*vec != nullptr){
**vec = (vector){ .capacity = args.cap };
}
return *vec != nullptr;
}
#define vec_create(vec, ...) \
vec_create(vec, (vc_args){.cap=16 __VA_OPT__(,) __VA_ARGS__ } )
typedef struct vector {
size_t capacity;
size_t size;
Type data[];
} vector;
typedef struct vc_args { size_t cap; } vc_args;
bool vec_create(vector * vec[static 1], vc_args args){
if (*vec != nullptr)
return false;
assert(args.cap > 0 && "Capacity must be greater than 0");
*vec = malloc(sizeof(**vec) +
sizeof(typeof(*(*vec)->data)[args.cap]))
if (*vec != nullptr){
**vec = (vector){ .capacity = args.cap };
}
return *vec != nullptr;
}
#define vec_create(vec, ...) \
vec_create(vec, (vc_args){.cap=16 __VA_OPT__(,) __VA_ARGS__ } )