www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How would the equivalent C type be in D?

reply rempas <rempas tutanota.com> writes:
I'm looking into 
[this](https://www.x.org/releases/X11R7.7/doc/libxcb/tutorial/index.html)
tutorial to learn XCB and I'm trying to write the code in D with betterC. In
the section 9.1 (sorry, I cannot give a section link, the article does not give
us this ability), I'm facing a problem and my program exits with the exit code:
"-11". I suspect that this happens because I haven't translated the following
code the right way:

```d
uint32_t value[1];
value[0] = screen.black_pixel;
xcb_create_gc(connection, black, win, mask, value);
```

I originally tried to translate this as:

```d
uint[1] value;
value[0] = screen.black_pixel;
xcb_create_gc(connection, black, win, mask, value);
```

But then, when I tried to compile the program, I got the 
following error:

```
Error: function `headers.xcb_create_gc(xcb_connection_t* c, uint 
cid, uint drawable, uint value_mask, const(void)* value_list)` is 
not callable using argument types `(xcb_connection_t*, uint, 
uint, uint, uint[1])`
src/draw.d(18,16):        cannot pass argument `value` of type 
`uint[1]` to parameter `const(void)* value_list`
```

So I thought of doing the following:

```d
uint* value;
value[0] = screen.black_pixel;
xcb_create_gc(connection, black, win, mask, value);
```

Now the program complies but I get the "-11" exit code. Another 
thing I thought (which is probably the same thing under the hood 
but done a different way):

```d
const(void)* value;
(cast(ubyte*)value)[0] = screen.black_pixel;
xcb_create_gc(connection, black, win, mask, value);
```

Same results. Any ideas?
Mar 01 2023
parent reply FeepingCreature <feepingcreature gmail.com> writes:
On Wednesday, 1 March 2023 at 08:12:05 UTC, rempas wrote:
 I'm looking into 
 [this](https://www.x.org/releases/X11R7.7/doc/libxcb/tutorial/index.html)
tutorial to learn XCB and I'm trying to write the code in D with betterC. In
the section 9.1 (sorry, I cannot give a section link, the article does not give
us this ability), I'm facing a problem and my program exits with the exit code:
"-11". I suspect that this happens because I haven't translated the following
code the right way:

 ```d
 uint32_t value[1];
 value[0] = screen.black_pixel;
 xcb_create_gc(connection, black, win, mask, value);
 ```

 I originally tried to translate this as:

 ```d
 uint[1] value;
 value[0] = screen.black_pixel;
 xcb_create_gc(connection, black, win, mask, value);
 ```

 But then, when I tried to compile the program, I got the 
 following error:

 ```
 Error: function `headers.xcb_create_gc(xcb_connection_t* c, 
 uint cid, uint drawable, uint value_mask, const(void)* 
 value_list)` is not callable using argument types 
 `(xcb_connection_t*, uint, uint, uint, uint[1])`
 src/draw.d(18,16):        cannot pass argument `value` of type 
 `uint[1]` to parameter `const(void)* value_list`
 ```

 So I thought of doing the following:

 ```d
 uint* value;
 value[0] = screen.black_pixel;
 xcb_create_gc(connection, black, win, mask, value);
 ```

 Now the program complies but I get the "-11" exit code. Another 
 thing I thought (which is probably the same thing under the 
 hood but done a different way):

 ```d
 const(void)* value;
 (cast(ubyte*)value)[0] = screen.black_pixel;
 xcb_create_gc(connection, black, win, mask, value);
 ```

 Same results. Any ideas?
11 is SIGSEGV. A segfault, or access violation, happens when you try to access unallocated memory. In this case, let me annotate your code so it's easier to see what's happening: ```d // null is the default value for a pointer uint* value = null; // because `value` is null, the first index also lies at null. assert(&value[0] is null); // So we try to store screen.black_pixel at memory address null, which is unallocated. value[0] = screen.black_pixel; xcb_create_gc(connection, black, win, mask, value); ``` As there is no memory segment allocated at address null, the CPU indicates a segmentation fault, which terminates the program. So yes, `xcb_create_gc` wants a `uint*` parameter, but not just any `uint*` will do: it has to point to valid memory. Going back to the first snippet, what's happening here is that in C, arrays implicitly convert to pointers, because C doesn't have a notion of array types as distinct from pointer types. So you can have a variable declared as `uint[1]`, but pass it to a parameter that expects `uint*`, and the value that is passed will just be the address of the first field of the array. However, even in C, if you try to define `value` as `uint*`, it will segfault in the same way. Instead, in D, you need to tell the compiler to define an array of size 1, and then pass a pointer to the array's first member explicitly: ```d uint32_t[1] value; value[0] = screen.black_pixel; // this is what C does under the hood xcb_create_gc(connection, black, win, mask, &value[0]); ``` Or shorter, but with the same effect: ```d uint32_t[1] value; value[0] = screen.black_pixel; xcb_create_gc(connection, black, win, mask, value.ptr); ```
Mar 01 2023
next sibling parent FeepingCreature <feepingcreature gmail.com> writes:
On Wednesday, 1 March 2023 at 08:26:07 UTC, FeepingCreature wrote:
 ```d
 uint32_t[1] value;
 value[0] = screen.black_pixel;
 xcb_create_gc(connection, black, win, mask, value.ptr);
 ```
To expand on this: ```d uint32_t[2] value; uint32_t* value_ptr = value.ptr; // We are allowed to access the pointer at index 0 // because we declared the value it points to, to be size 2. value_ptr[0] = 0; // This is also allowed, because `value_ptr` is // a pointer to two sequential `uint32_t` in memory. value_ptr[1] = 0; // But this access would segfault, because it's trying to write // to the third element of a two-element array: value_ptr[2] = 0; ``` Note: I just lied; `value_ptr[2]` would not segfault, for somewhat technical reasons; but it *would* corrupt your program's memory. At any rate, it's an invalid operation.
Mar 01 2023
prev sibling parent reply rempas <rempas tutanota.com> writes:
On Wednesday, 1 March 2023 at 08:26:07 UTC, FeepingCreature wrote:
 11 is SIGSEGV. A segfault, or access violation, happens when 
 you try to access unallocated memory. In this case, let me 
 annotate your code so it's easier to see what's happening:

 ```d
 // null is the default value for a pointer
 uint* value = null;
 // because `value` is null, the first index also lies at null.
 assert(&value[0] is null);
 // So we try to store screen.black_pixel at memory address 
 null, which is unallocated.
 value[0] = screen.black_pixel;
 xcb_create_gc(connection, black, win, mask, value);
 ```

 As there is no memory segment allocated at address null, the 
 CPU indicates a segmentation fault, which terminates the 
 program.

 So yes, `xcb_create_gc` wants a `uint*` parameter, but not just 
 any `uint*` will do: it has to point to valid memory. Going 
 back to the first snippet, what's happening here is that in C, 
 arrays implicitly convert to pointers, because C doesn't have a 
 notion of array types as distinct from pointer types. So you 
 can have a variable declared as `uint[1]`, but pass it to a 
 parameter that expects `uint*`, and the value that is passed 
 will just be the address of the first field of the array. 
 However, even in C, if you try to define `value` as `uint*`, it 
 will segfault in the same way. Instead, in D, you need to tell 
 the compiler to define an array of size 1, and then pass a 
 pointer to the array's first member explicitly:

 ```d
 uint32_t[1] value;
 value[0] = screen.black_pixel;
 // this is what C does under the hood
 xcb_create_gc(connection, black, win, mask, &value[0]);
 ```

 Or shorter, but with the same effect:

 ```d
 uint32_t[1] value;
 value[0] = screen.black_pixel;
 xcb_create_gc(connection, black, win, mask, value.ptr);
 ```
Thank you! You are amazing for explaining it! I was so focused on thinking that I'm doing something wrong with the type that I didn't noticed that the pointers, points to nowhere so the function obviously has nowhere to write to. Like... OMG! And I want to make a fully fledged compiler when making stupid mistakes like that. Btw, When I executed the program, I got "Error Program exited with code -11". You said that the code was "11". What about that dash? If it is not a "minus" and it's just the dash symbol, then what's the idea?
Mar 01 2023
next sibling parent reply FeepingCreature <feepingcreature gmail.com> writes:
On Wednesday, 1 March 2023 at 09:37:48 UTC, rempas wrote:
 Thank you! You are amazing for explaining it! I was so focused 
 on thinking that I'm doing something wrong with the type that I 
 didn't noticed that the pointers, points to nowhere so the 
 function obviously has nowhere to write to. Like... OMG! And I 
 want to make a fully fledged compiler when making stupid 
 mistakes like that. Btw, When I executed the program, I got 
 "Error Program exited with code -11". You said that the code 
 was "11". What about that dash? If it is not a "minus" and it's 
 just the dash symbol, then what's the idea?
Yay! Yes, that is a bit weird. First of all, the actual signal is 11 ``` $ grep SIGSEGV /usr/include/bits -R /usr/include/bits/signum-generic.h:#define SIGSEGV 11 /* Invalid access to storage. */ ``` As per the POSIX spec https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap0 .html#tag_18_21_18. signal exits must be reported with exit codes above 128. Customarily, shells will simply add 128 to the signal: ``` $ cat test.c; gcc test.c -otestc; ./testc; echo $? int main() { int* ip = 0; *ip = *ip; return 0; } Segmentation fault 139 ``` 139 being 128 + 11, but POSIX does not specify *how* the signal code is converted to an exit code. For instance, Python reports a signal 11 exit as -11. Strictly speaking, -11 is "above 128" in two's complement, corresponding to unsigned 245. But I don't know why Python does this. Presumably your shell does it the same way?
Mar 07 2023
parent rempas <rempas tutanota.com> writes:
On Tuesday, 7 March 2023 at 09:05:45 UTC, FeepingCreature wrote:
 Yay!

 Yes, that is a bit weird. First of all, the actual signal is 11

 [...]
Thank you for the info!
Mar 07 2023
prev sibling parent FeepingCreature <feepingcreature gmail.com> writes:
On Wednesday, 1 March 2023 at 09:37:48 UTC, rempas wrote:
 Thank you! You are amazing for explaining it! I was so focused 
 on thinking that I'm doing something wrong with the type that I 
 didn't noticed that the pointers, points to nowhere so the 
 function obviously has nowhere to write to. Like... OMG! And I 
 want to make a fully fledged compiler when making stupid 
 mistakes like that. Btw, When I executed the program, I got 
 "Error Program exited with code -11". You said that the code 
 was "11". What about that dash? If it is not a "minus" and it's 
 just the dash symbol, then what's the idea?
Yay! (Definitely make a compiler, it's a great way to learn.) Yes, that is a bit weird. First of all, the actual signal is 11 ``` $ grep SIGSEGV /usr/include/bits -R /usr/include/bits/signum-generic.h:#define SIGSEGV 11 /* Invalid access to storage. */ ``` As per the POSIX spec https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap0 .html#tag_18_21_18. signal exits must be reported with exit codes above 128. Customarily, shells will simply add 128 to the signal: ``` $ cat test.c; gcc test.c -otestc; ./testc; echo $? int main() { int* ip = 0; *ip = *ip; return 0; } Segmentation fault 139 ``` 139 being 128 + 11, but POSIX does not specify *how* the signal code is converted to an exit code. For instance, Python reports a signal 11 exit as -11. Strictly speaking, -11 is "above 128" in two's complement, corresponding to unsigned 245. But I don't know why Python does this. Presumably your shell does it the same way?
Mar 07 2023