framapiaf.org est l'un des nombreux serveurs Mastodon indépendants que vous pouvez utiliser pour participer au fédiverse.
Un service Mastodon fourni par l'association d’éducation populaire Framasoft.

Administré par :

Statistiques du serveur :

1,4K
comptes actifs

#include

5 messages3 participants0 message aujourd’hui
A répondu dans un fil de discussion

It looks like CW by default auto-includes any Mac headers you need, but at the same time stdlib stuff like "strlen" isn't working even with a manual #include <strings.h> which is the point where I'm starting to look at "maybe I should read a book instead of just poking at things randomly!" (2/2)

A répondu dans un fil de discussion

@jduck I mean, if it convinces you...

$ cat blub.c
#include <stdlib.h>
#include <stdio.h>
struct foo {
long a;
int b;
int arr[];
};
int main(void) {
struct foo *a = malloc(sizeof(struct foo) + sizeof(int)*3);
struct foo *b = malloc(sizeof(struct foo) + sizeof(int)*3);
if (!a || !b)
return 1;

a->a = 1;
a->b = 2;
for (int i=0; i<3; i++)
a->arr[i] = i + 123456;

b->a = 101;
b->b = 102;
for (int i=0; i<3; i++)
b->arr[i] = i + 100;

*b = *a;

for (int i=0; i<3; i++)
printf("%d ", b->arr[i]);
printf("\n");
}
$ gcc -o blub blub.c
$ ./blub
123456 101 102

Why does the C standard not mention any UB in its definition of offsetof()? Is it implicit somewhere else that doing offsetof(struct foo, arr[SIZE_MAX]) on a struct containing a flexible array member is UB?

Both GCC and clang don't diagnose anything here and compile it to a "return 0":

#include <stddef.h>
#include <inttypes.h>
struct foo {
int a;
int arr[];
};
unsigned long func(void) {
return offsetof(struct foo, arr[SIZE_MAX]);
}

godbolt.org/z/rx7rqvh7j

godbolt.orgCompiler Explorer - Cstruct foo { int a; int arr[]; }; unsigned long func(void) { return offsetof(struct foo, arr[SIZE_MAX]); }

Funny standard C behavior - assigning a struct with flexible array member can copy parts of the flexible array member:

$ cat vla_assign.c
#include <stdlib.h>
#include <stdio.h>
struct foo {
long a;
int b;
int arr[];
};
int main(void) {
struct foo *a = malloc(sizeof(struct foo) + sizeof(int)*3);
struct foo *b = malloc(sizeof(struct foo) + sizeof(int)*3);
if (!a || !b)
return 1;

a->a = 1;
a->b = 2;
for (int i=0; i<3; i++)
a->arr[i] = i;

b->a = 101;
b->b = 102;
for (int i=0; i<3; i++)
b->arr[i] = i + 100;

*b = *a;

for (int i=0; i<3; i++)
printf("%d ", b->arr[i]);
printf("\n");
}
$ gcc -Wall -Wextra -pedantic -o vla_assign vla_assign.c
$ ./vla_assign
0 101 102
A répondu dans un fil de discussion

@whitequark @ronya That is wild because the whole reason for that separate parser is to be able to reindex individual files without paying attention to the #include graph or anything.

It doesn't do this for me, but that's using "full" VS, which shares the parser(s) but not the layer that orchestrates them. (But also both VS and Code are prone to behaving in similarly broken ways.)

inspired by @pinskia mentioning musttail, today I learned that you can implement state machines in C such that state transitions are implemented as calls:

#include <stdlib.h>
#include <stdio.h>

#define VOID __attribute__((noinline)) void
#define JUMP [[clang::musttail]] return

static char *input;
static int acc = 0;
static int state = 0;

VOID initial_state(void);

VOID digit(void) {
acc += *(input++) - '0';
JUMP initial_state();
}
VOID separator(void) {
state = acc;
acc = 0;
input++;
JUMP initial_state();
}
VOID add(void) {
state += acc;
acc = 0;
input++;
JUMP initial_state();
}
VOID minus(void) {
state -= acc;
acc = 0;
input++;
JUMP initial_state();
}

VOID initial_state(void) {
switch (*input) {
case '0'...'9':
JUMP digit();
case ' ':
JUMP separator();
case '+':
JUMP add();
case '-':
JUMP minus();
default:
printf("result: %d\n", state);
exit(0);
}
}

int main(int argc, char **argv) {
puts("welcome to my calculator");
input = argv[1];
initial_state();
}

compiles to stuff like this, all jumps:

add:
mov eax, dword ptr [rip + acc]
add dword ptr [rip + state], eax
mov dword ptr [rip + acc], 0
inc qword ptr [rip + input]
jmp initial_state

And the security benefits are obvious! The less stack you have, the less potential for the stack pointer being hijacked! 😆

En réponse à Jann Horn

@jann I mean equally:

#define _GNU_SOURCE
#include <err.h>
#include <stdio.h>
#include <sys/mman.h>
int main(void) {
char *p = mmap(NULL, 0x2000, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
if (p == MAP_FAILED) err(1, "mmap");
p[0x1000] = 'X';
if (madvise(&p[0x1000], 0x1000, MADV_DONTNEED)) err(1, "madvise");
// that 'X' we just wrote... is it gone?
// nope, let's bring it back!
printf("p[0x1000]='%c'\n", p[0x1000]);
}

fun Linux fact: because MAP_SHARED|MAP_ANONYMOUS is actually a file-backed mapping under the hood, unmapping part of such a mapping does not discard the data stored in that part:

$ cat mremap.c
#define _GNU_SOURCE
#include <err.h>
#include <stdio.h>
#include <sys/mman.h>
int main(void) {
char *p = mmap(NULL, 0x2000, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
if (p == MAP_FAILED) err(1, "mmap");
p[0x1000] = 'X';
if (munmap(p+0x1000, 0x1000)) err(1, "munmap");
// that 'X' we just wrote... is it gone?
// nope, let's bring it back!
p = mremap(p, 0x1000, 0x2000, MREMAP_MAYMOVE);
if (p == MAP_FAILED) err(1, "mremap");
printf("p[0x1000]='%c'\n", p[0x1000]);
}
$ gcc -o mremap mremap.c
$ ./mremap
p[0x1000]='X'
$

Many file formats have some kinds of inclusion directive, like "#include" for C, "\input" for LaTeX, "\transclude" for forester.

I would like to have a text editor feature that allows me to visually expand an inclusion directive in the text buffer, just like how folds of text regions work, while actual changes are still made to the referenced file.

This would be very useful when working with projects with many inter-linked files because most text editors are not very good at jumping around files/buffers.
However, this feature looks impossible to implement nicely in vim. Does anyone know an editor that supports this or is hopeful to support this?

ok i hit this weekend's goal:

#include <windows.h>

int main(int argc, char **argv) {
char computer_name_buf[1024];
DWORD buf_size = sizeof(computer_name_buf);
GetComputerNameA(computer_name_buf, &buf_size);
printf("hi from main: computer name %s\n", computer_name_buf);
return 0;
}

Time to get printf to the SIZE_MAX off the ground. Especially since it's not the type that matters for the precision specifier for the string size, it's the actual value.

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <assert.h>

int main() {
enum { COUNT = 10, BYTESIZE = INT_MAX / COUNT };
char* str = (char*)malloc(BYTESIZE + 1);
for (size_t i = 0; i < BYTESIZE; ++i) {
str[i] = 'a';
}
str[BYTESIZE] = '\0';
FILE* f = fopen("/dev/null", "w+");
[[maybe_unused]] int write_value = fprintf(f, "%.*s", BYTESIZE, str);
[[maybe_unused]] int large_write_value = fprintf(f, "%.*s %*.s %*.s %*.s %*.s %*.s %*.s %*.s %*.s %*.s %*.s",
BYTESIZE, str, BYTESIZE, str, BYTESIZE, str, BYTESIZE, str, BYTESIZE, str, BYTESIZE, str, BYTESIZE, str,
BYTESIZE, str, BYTESIZE, str, BYTESIZE, str, BYTESIZE, str);
free(str);
assert(write_value == BYTESIZE); // Well.
assert(large_write_value == -1); // ... Okay.
// this should let the other thing work out nicely, then.
return 0;
}

Wow, __builtin_dump_struct is an amazing clang feature, how did I never hear about this before?

$ cat test.c
#include <stdio.h>

struct nested {
int n;
};
struct foo {
int member_a;
unsigned long member_b;
char *str;
void *ptr;
struct nested nested;
};

int main(void) {
struct foo f = {
.member_a = 123,
.member_b = 0x4141414141414141,
.str = "foobar",
.ptr = &f,
.nested = {.n = 42}
};
__builtin_dump_struct(&f, printf);
}
$ clang -o test test.c && ./test
struct foo {
int member_a = 123
unsigned long member_b = 4702111234474983745
char * str = "foobar"
void * ptr = 0x7fff1df41b78
struct nested nested = {
int n = 42
}
}

The original version of this feature was introduced back in 2018 (though it was reimplemented since in 2022).

clang.llvm.orgClang Language Extensions — Clang 21.0.0git documentation
A répondu dans un fil de discussion

@screwtape @praetor @untakenusername @bughuntercat Just to beat the hell out of a dead horse (this one took longer):

C:
#include
#include
int main() {
int* arr = malloc(5 * sizeof(int));
if (!arr) return 1; // Check allocation success
for (int i = 0; i < 5; i++) {
arr[i] = i * 10;
}
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
free(arr);
return 0;
}

Common Lisp:
(loop for i from 0 below 5
collect (* i 10) into arr
finally (print arr))

Which language does low level things easier? Clearly Common Lisp does... (even if this is high level representation of low level things...) :ablobcatrave:

A répondu dans un fil de discussion

@screwtape @praetor @untakenusername @bughuntercat This deserves an example.

C:
#include
#include
int main() {
uint8_t x = 0xA5;
// Extract the high nibble: shift right by 4 bits then mask
uint8_t high_nibble = (x >> 4) & 0x0F;
printf("High nibble: %X\n", high_nibble);
return 0;
}

Common Lisp:
(let ((x #xA5))
(format t "High nibble: ~X~%" (ldb (byte 4 4) x)))

This is how I started using #lisp from the very early days. So I see it as an easier way to do low level things. The rest (OOP and all) are things pretty much all modern languages do easily.

I recently found one of my first very low level Lisp programs. I'll post it one day. It is ethically questionable though, because it outputs DOS-based viruses lol.

If you want me to hate you forever, a good way to do this is to share sample code as a isolated function in a blockquote, which produces a dozen 'symbol not found' errors when punched into actual code because you *didn't* include a blockquote containing the half-dozen #include or `using` or `import` statements that would be needed to bring the various API calls and types you reference into scope