View previous topic :: View next topic |
Author |
Message |
pjp Administrator


Joined: 16 Apr 2002 Posts: 20606
|
Posted: Sat Apr 19, 2025 6:23 am Post subject: [solved] Questions about using strtonum from libbsd |
|
|
My first question is how to make strtonum available to a program (include and linking). man strtonum: | SYNOPSIS
#include <limits.h>
#include <stdlib.h>
(See libbsd(7) for include usage.) | man libbsd: | The library can be used in an overlay mode, which is the preferred way, so
that the code is portable and requires no modification to the original BSD
code. This can be done easily with the pkgconf(1) library named libbsd-
overlay. Or by adding the system-specific include directory with the bsd/
suffix to the list of system include paths. With gcc this could be
-isystem ${includedir}/bsd. In addition the LIBBSD_OVERLAY pre-processor
variable needs to be defined. The includes in this case should be the
usual system ones, such as <unistd.h>.
The other way to use the library is to use the namespaced headers, which is
a discouraged way, being less portable as it makes using libbsd mandatory
and it will not work on BSD-based systems, and requires modifying original
BSD code. This can be done with the pkgconf(1) library named libbsd. The
includes in this case should be namespaced with bsd/, such as
<bsd/unistd.h>. | My understanding is that I'm using the second method. Is the first, "preferred" method possible? If so, how?
I have includes as: Code: | #include <stdio.h>
#include <limits.h> // UINT_MAX
#include <bsd/unistd.h> // LIBBSD_OVERLAY variable definition.
#include <bsd/stdlib.h> // strtonum() | And compile it this way (it works): Code: | $ gcc ex-strtonum.c -I bsd -lbsd |
The second quesition is with regards to the strtonum example usage: man strtonum: | int iterations;
const char *errstr;
iterations = strtonum(optarg, 1, 64, &errstr);
if (errstr)
errx(1, "number of iterations is %s: %s", errstr, optarg); | When I first tried using it, I didn't notice the lack of an alloc for errstr.
Am I mistaken that an allocaiton is needed for errstr? I was surprised to find that it compiles without any errors: Code: | $ gcc ex-strtonum.c -I bsd -lbsd -O0 -g3 -fsanitize=address,undefined |
b() is my unsuccessful attempt to provide an array as memory for errstr. Still no errors, but
incorrect results due to errstr (I'm guessing not being null?): Code: | $ ./a.out
a():
Converted string 123 to integer 123.
b():
strtonum error: : [123]
::Converted string 123 to integer 123. |
My last question is whether or not an array can be used instead of an allocaiton function to support errstr (if so, how)?
The complete program: Code: | #include <stdio.h>
#include <limits.h> // UINT_MAX
#include <bsd/unistd.h> // LIBBSD_OVERLAY variable definition.
#include <bsd/stdlib.h> // strtonum()
void a(void);
void b(void);
int main(void) {
printf("a():\n");
a();
printf("b():\n");
b();
}
void a(void) {
const char s[] = "123";
const char *errstr;
int n = 0;
n = strtonum(s, 0, UINT_MAX, &errstr);
if (errstr) {
printf("\tstrtonum error: %s: [%s]\n", errstr, s);
} else {
printf("\tConverted string %s to integer %d.\n", s, n);
}
}
void b(void) {
const char s[] = "123";
const char errstr[64];
int n = 0;
n = strtonum(s, 0, UINT_MAX, (const char **)errstr);
if (errstr) {
printf("\tstrtonum error: %s: [%s]\n", errstr, s);
} else {
printf("\tConverted string %s to integer %d.\n", s, n);
}
printf("\t::Converted string %s to integer %d.\n", s, n);
} |
This started because I wanted to convert some string numbers to integers and remembered atoi() had issues. At least some of strtonum's man page is less confusing than that of strtol. Plus, min, max is a nice feature. _________________ Quis separabit? Quo animo?
Last edited by pjp on Wed Apr 23, 2025 12:17 am; edited 1 time in total |
|
Back to top |
|
 |
logrusx Advocate


Joined: 22 Feb 2018 Posts: 2937
|
Posted: Sat Apr 19, 2025 7:54 am Post subject: |
|
|
Quote: | The library can be used in an overlay mode, which is the preferred way, so that the code is portable and requires no modification to the original BSD code. This can be done easily with the pkgconf(1) library named libbsd-overlay. |
Code: | pkg-config --cflags libbsd-overlay |
test.c: | #include <limits.h>
#include <stdlib.h>
#include <err.h>
int main() {
int iterations;
const char *errstr;
char* optarg = "3";
iterations = strtonum(optarg, 1, 64, &errstr);
if (errstr)
errx(1, "number of iterations is %s: %s", errstr, optarg);
} |
Code: | gcc $(pkg-config --cflags libbsd-overlay) test.c |
This is my 20+ y. rusty C. I hope it helps.
Best Regards,
Georgi |
|
Back to top |
|
 |
bstaletic Guru

Joined: 05 Apr 2014 Posts: 493
|
Posted: Sat Apr 19, 2025 3:05 pm Post subject: |
|
|
By doing (const char**)array and pass it to the function, the following happens:- Array-to-pointer decay happens before the cast, so we're at (const char**)char_ptr
- Reinterpreting that pointer as a pointer of different type does not affect the value, just smacks the type system across the face.
- Passing the reinterpreted pointer to a function passes a copy. Whatever strtonum does, does not matter as the value of the original array will remain unchanged.
Here's a simpler example: Code: | void f(int* ip) { *ip = 5; }
int main(void) {
int x = 4;
f((int*)x);
printf("%d\n", x); // Still 4
f(&x);
print("%d\n", x); // Now 5
} |
As for the allocation part, logically, if libbsd were allocating the buffer behind your back, the man page should have told you how to deallocate.
Since it doesn't mention deallocation, I would assume it doesn't allocate either.
Looking at the implementation, the passed pointer is pointed at a string literal, which has static lifetime. |
|
Back to top |
|
 |
GDH-gentoo Veteran


Joined: 20 Jul 2019 Posts: 1857 Location: South America
|
Posted: Sat Apr 19, 2025 3:05 pm Post subject: Re: Questions about using strtonum from libbsd |
|
|
pjp wrote: | My understanding is that I'm using the second method. |
Yes.
pjp wrote: | Is the first, "preferred" method possible? If so, how? |
With special CFLAGS. libbsd provides a pkg-config file so that you don't have to remember the incantation; logrusx showed how to use it.
pjp wrote: | I have includes as: Code: | #include <stdio.h>
#include <limits.h> // UINT_MAX
#include <bsd/unistd.h> // LIBBSD_OVERLAY variable definition.
#include <bsd/stdlib.h> // strtonum() |
|
You don't need <bsd/unistd.h> here, and also, in overlay mode, you just write #include <stdlib.h> in the source file.
pjp wrote: | Am I mistaken that an allocaiton is needed for errstr? |
It is not. You just provide a pointer to a (modifiable) object of pointer type, so that strtonum() can store a value in the object pointed to, like you did in a().
libbsd's implementation has all possible error messages stored as string literals.
pjp wrote: | Code: | void b(void) {
const char s[] = "123";
const char errstr[64];
// ...
n = strtonum(s, 0, UINT_MAX, (const char **)errstr);
// ...
} |
|
This has undefined behaviour, errstr here has type "array of 64 const char", is implicitly converted to "pointer to const char" before the cast, and then to an incompatible pointer type by the cast (pointer to pointer to const char).
EDIT:
logrusx wrote: | Code: | gcc $(pkg-config --cflags libbsd-overlay) test.c |
|
This does compiling and linking, so don't forget the libraries:
Code: | gcc $(pkg-config --cflags libbsd-overlay) test.c $(pkg-config --libs libbsd-overlay) |
_________________
NeddySeagoon wrote: | I'm not a witch, I'm a retired electronics engineer  |
Ionen wrote: | As a packager I just don't want things to get messier with weird build systems and multiple toolchains requirements though  |
|
|
Back to top |
|
 |
logrusx Advocate


Joined: 22 Feb 2018 Posts: 2937
|
Posted: Sat Apr 19, 2025 4:23 pm Post subject: Re: Questions about using strtonum from libbsd |
|
|
[quote="GDH-gentoo"] pjp wrote: |
EDIT:
logrusx wrote: | Code: | gcc $(pkg-config --cflags libbsd-overlay) test.c |
|
This does compiling and linking, so don't forget the libraries:
Code: | gcc $(pkg-config --cflags libbsd-overlay) test.c $(pkg-config --libs libbsd-overlay) |
|
What's the difference? I first tried with both, didn't matter and dropped the second.
Best Regards,
Georgi |
|
Back to top |
|
 |
GDH-gentoo Veteran


Joined: 20 Jul 2019 Posts: 1857 Location: South America
|
Posted: Sat Apr 19, 2025 5:26 pm Post subject: Re: Questions about using strtonum from libbsd |
|
|
logrusx wrote: | What's the difference? I first tried with both, didn't matter and dropped the second. |
If you try building this:
test.c
Code: | #include <stdlib.h>
int main() {
const char *errs;
long long n = strtonum("12", 0, 20, &errs);
} |
Code: | gcc $(pkg-config --cflags libbsd-overlay) test.c |
expands to:
Code: | gcc -isystem /usr/include/bsd -DLIBBSD_OVERLAY test.c |
and
Code: | gcc $(pkg-config --cflags libbsd-overlay) test.c $(pkg-config --libs libbsd-overlay) |
expands to:
Code: | gcc -isystem /usr/include/bsd -DLIBBSD_OVERLAY test.c -lbsd |
The second form links with the library, and the first one fails because there is no definition of strtonum() anywhere:
Code: | /usr/bin/ld: /tmp/ccLOaYRE.o: in function `main':
test.c:(.text+0x37): undefined reference to `strtonum'
collect2: error: ld returned 1 exit status |
_________________
NeddySeagoon wrote: | I'm not a witch, I'm a retired electronics engineer  |
Ionen wrote: | As a packager I just don't want things to get messier with weird build systems and multiple toolchains requirements though  |
|
|
Back to top |
|
 |
logrusx Advocate


Joined: 22 Feb 2018 Posts: 2937
|
Posted: Sat Apr 19, 2025 5:33 pm Post subject: Re: Questions about using strtonum from libbsd |
|
|
GDH-gentoo wrote: | and the first one fails because there is no definition of strtonum() anywhere:
Code: | /usr/bin/ld: /tmp/ccLOaYRE.o: in function `main':
test.c:(.text+0x37): undefined reference to `strtonum'
collect2: error: ld returned 1 exit status |
|
Thanks! I tried that again and got exactly the same error with my test file posted above. I must have overlooked the error before.
What I think I did at first and this is where the executable came from is:
Code: | $ pkg-config --cflags --libs libbsd-overlay
-isystem /usr/include/bsd -DLIBBSD_OVERLAY -lbsd |
So you don't need to invoke pkg-config twice, but add all necessary options (and perhaps modules?). It even worked like that:
Code: | $ pkg-config --cflags libbsd-overlay --libs libbsd-overlay
-isystem /usr/include/bsd -DLIBBSD_OVERLAY -lbsd |
So I guess you can put multiple options and list of modules. Actually the man page says it:
Quote: | SYNOPSIS
pkgconf [options] [list of modules]
|
Best Regards,
Georgi
p.s. it's not clear what OP's concerns are and why he is choosing to use strtonum. This looks like unreasonable headache to me. |
|
Back to top |
|
 |
GDH-gentoo Veteran


Joined: 20 Jul 2019 Posts: 1857 Location: South America
|
Posted: Sun Apr 20, 2025 4:55 pm Post subject: Re: Questions about using strtonum from libbsd |
|
|
logrusx wrote: | p.s. it's not clear what OP's concerns are and why he is choosing to use strtonum. This looks like unreasonable headache to me. |
pjp wrote: | This started because I wanted to convert some string numbers to integers and remembered atoi() had issues. At least some of strtonum's man page is less confusing than that of strtol. Plus, min, max is a nice feature. |
The OpenBSD people believe their extension is easier to use correctly than the C standard library interfaces, and pjp seems to agree
Successful conversions of strings to numbers are easy, the problem are unsuccessful ones: not a valid representation of a number, an empty string, a number that is out of the range of values that can be represented in the target type, etc.
The atox() functions have undefined behaviour if the conversion is unsuccessful —presumably for allowing simplistic implementations—, so they can't be used in portable code when the programmer can't guarantee that the conversion will be successful (e. g. when dealing with untrusted input that must be validated before use), and the strtox() functions do require many checks for knowing if the conversion was unsuccessful and why (e. g. if the program wants to display a helpful error message). _________________
NeddySeagoon wrote: | I'm not a witch, I'm a retired electronics engineer  |
Ionen wrote: | As a packager I just don't want things to get messier with weird build systems and multiple toolchains requirements though  |
|
|
Back to top |
|
 |
pjp Administrator


Joined: 16 Apr 2002 Posts: 20606
|
Posted: Wed Apr 23, 2025 12:04 am Post subject: |
|
|
Thanks for the comments.
Regarding pkg-config, I think I dismissed that believing it was a bsd tool. I focused on the libbsd man page that mentioned: With gcc this could be -isystem ${includedir}/bsd. Only when I did that, it produced a lot of error output about nested depth exceeding maximum).
With the information about how to use pkg-config, it is more apparent what I was missing... the -D... and -lbsd (the latter not mentioned in the man page): Code: | $ gcc ex-strtonum.c -isystem /usr/include/bsd -DLIBBSD_OVERLAY -lbsd |
So that's cleared up. Thank you very much. For my simple uses, I think I'll stick with #include <bsd/stdlib.h> as it is less for me to type and remember. For a bigger project, I hope to remember pkg-config, although that seems primarily useful for software that will be distributed and/or used on multiple different kinds of systems.
As for why I chose strtonum, it was mentioned as the "first choice" then either stronol. Rather than go down some other hole trying to figure out which one was "best", I just chose strtonum.
Which brings me to the "easier" to use point. I think it's mostly in how GNU writes documentation: Code: | long strtol(const char *restrict nptr, char **_Nullable restrict endptr, int base); | This requires a lot of energy to decrypt what I need to know. I know of 'restrict', but that's it. So I have to parse that out of what I'm reading. I have no idea what 'nptr' is other than probably a pointer. More energy to parse. Then a double char pointer to whatever _Nullable means and a pointer variable somehow related to and 'end' of something. I already don't want to deal with this. At least base I can guess that it is the base for a numbering system.
Naturally I went on to read more of the documentation in the man page. Yes, I get it. nptr is the string I want to convert. enptr I don't care about, but is something else I have to do to get 0 - 9999 out of a csv file.
I understand that as I read stuff like that I'll understand it more easily, but until then, it isn't fun, it's draining. Anywya, that was after having tried strtonum and receiving errors about how to use it (I was forgetting to link to it, -lbsd is less intuitive to -libbsd -- but still better than -lm *shakes fist*).
So after that and reading the strtol man page, I just went back to strtonum and figured out the linking that I wasn't performing.
And while there are similarities and strtonum has it's own "what does that mean" for me, this is much easier to get through: Code: | strtonum(const char *nptr, long long minval, long long maxval, const char **errstr); | Here errstr was (and is, sort of) the only confusing part. But I was able to just use the example and worry about that part afterward.
Thanks again! _________________ Quis separabit? Quo animo? |
|
Back to top |
|
 |
pjp Administrator


Joined: 16 Apr 2002 Posts: 20606
|
Posted: Wed Apr 23, 2025 12:15 am Post subject: |
|
|
bstaletic wrote: | By doing (const char**)array and pass it to the function, the following happens:- Array-to-pointer decay happens before the cast, so we're at (const char**)char_ptr
- Reinterpreting that pointer as a pointer of different type does not affect the value, just smacks the type system across the face.
- Passing the reinterpreted pointer to a function passes a copy. Whatever strtonum does, does not matter as the value of the original array will remain unchanged.
| First I simply have to say that for a very long time I have completely misunderstood what char *foo = "Some text here" is. More on that later.
(2) is what I was trying to do, that is, smack the type system. I was trying to force it to use the array as storage rather than using a malloc type function to provide storage to errstr. Naturally it didn't work, and I tried several other ways. One of those ways included use of '&'.
I'm mostly, sort of comfortable with passing pointers to change them, but I still have to stumble over it from time to time. Preceding this example I had an "Oh, yeah" moment with while(buffer) vs. while(*buffer). I was trying to do it from memory with the first version and also comparing it to != '\0' in the while loop. I prefer the clarity of showing the comparison, but I don't think it worked -- or maybe I forgot to try that version while(*buffer != '\0').
bstaletic wrote: | As for the allocation part, logically, if libbsd were allocating the buffer behind your back, the man page should have told you how to deallocate.
Since it doesn't mention deallocation, I would assume it doesn't allocate either.
Looking at the implementation, the passed pointer is pointed at a string literal, which has static lifetime. | That makes sense. But this gets back to the misunderstanding I had.
Instead of interpreting the lack of reference to allocation and deallocation in the obvious way you mention, I interpreted it as "the implied allocation is obvious."
My misunderstanding was that in char *foo = "Some text here" foo could not be altered, and that even the declaration without assignment could not be altered without first allocating memory to the pointer variable '*foo' followed by a strcpy (or similar) since assignment didn't occur at declaration.
In fact, when I first read your explanation, I thought you were describing that *errstr was using the pointer space to store data instead of a block of memory that would otherwise needed to have been provided.
So that took me a while to mentally untangle as that error in understanding has existed for a very long time.
Thanks for the help! _________________ Quis separabit? Quo animo? |
|
Back to top |
|
 |
Hu Administrator

Joined: 06 Mar 2007 Posts: 23335
|
Posted: Wed Apr 23, 2025 12:45 am Post subject: |
|
|
In my opinion, casts should only be added if you can explain why the compiler is wrong to stop you. The C type system is not as expressive as some younger languages, but the rules it does enforce are there to protect you. When you add a cast, you declare that you know better than the compiler what is happening, and that it should just let you do what you say you want.
To the use of char *foo = "text", while this is permitted in C, it is dangerous, since string literals are not modifiable and may be stored in read-only memory. Writing const char *foo = "text" would be safer, as it prohibits later trying to write through foo into the underlying buffer. |
|
Back to top |
|
 |
pjp Administrator


Joined: 16 Apr 2002 Posts: 20606
|
Posted: Wed Apr 23, 2025 7:39 pm Post subject: |
|
|
That seems like a good approach regarding use of casts. And I presume being able to make that call would first require that I understand how they work.
Hu wrote: | Writing const char *foo = "text" would be safer, as it prohibits later trying to write through foo into the underlying buffer. | Would you mind elaborating on this point, or possibly directing me to something that explains what's happening? I can change it with a new assignment (no errors with -Wall): Code: | const char *foo = "foo";
foo="bar"; | But not using array indexing: Code: | strconst.c: In function ‘main’:
strconst.c:17:20: error: assignment of read-only location ‘*(foo + (sizetype)i)’
17 | foo[i] = foo[i] - 65; | My first thought was that 'foo = bar' would use a new memory location, but that didn't appear to happen during a small number of tests. What is going on that one change to a read-only location is okay, but the other is not?
12.7 String Constants (gnu.org) doesn't really help much, except the last paragraph. Although I think by "string constant" it means a string literal, not a 'const char *'? Quote: | Be careful to avoid passing a string constant to a function that modifies the string it receives. The memory where the string constant is stored may be read-only, which would cause a fatal SIGSEGV signal that normally terminates the function (see Signals. Even worse, the memory may not be read-only. Then the function might modify the string constant, thus spoiling the contents of other string constants that are supposed to contain the same value and are unified by the compiler. | Unfortunately I'm not yet able to distill the practical meaning of 'restrict' at cppreference, the use of which is specified in strtol, strcpy, and memcpy. I thought perhaps that might have helped.
https://en.cppreference.com/w/c/language/restrict _________________ Quis separabit? Quo animo? |
|
Back to top |
|
 |
Hu Administrator

Joined: 06 Mar 2007 Posts: 23335
|
Posted: Wed Apr 23, 2025 8:28 pm Post subject: |
|
|
pjp wrote: | And I presume being able to make that call would first require that I understand how they work. | Yes. pjp wrote: | Hu wrote: | Writing const char *foo = "text" would be safer, as it prohibits later trying to write through foo into the underlying buffer. | Would you mind elaborating on this point, or possibly directing me to something that explains what's happening? | You need to distinguish between a pointer that is constant versus a pointer to a constant:- char *p - a variable that can be reassigned, and that points to chars that themselves can be modified
Code: | char a[3] = "", b[2] = "x";
const char c[1] = "";
char *p = a;
p = b; // OK, p is mutable, we can redirect it to point somewhere else
++*p; // OK, p points to mutable char, so we can write through p to change the underlying data
p = c; // error, cannot convert `const char *` to `char *` | const char *p - a variable that can be reassigned to point at something else, but whatever it points at is const and cannot be modified. Code: | char a[3] = "", b[2] = "x";
const char c[1] = "";
const char *p = a; // OK, `char *` can convert to `const char *`
p = b; // OK, p is mutable, we can redirect it to point somewhere else
++*p; // error, p points to const char, so we cannot write through p to change the underlying data, even though ++a[0] would be legal
p = c; // OK | char *const p - a variable that cannot be reassigned, and always points to where it was first initialized, but which can be used to change the underlying storage Code: | char a[3] = "", b[2] = "x";
const char c[1] = "";
char *const p = a;
p = b; // error, p is const, so any assignment to it is invalid
++*p; // OK, p points to mutable char, so we can write through p to change the underlying data
p = c; // double error, p is const, and even if were not, we cannot convert `const char *` to `char *` | const char *const p - a variable that cannot be reassigned, and cannot be used to change the underlying storage Code: | char a[3] = "", b[2] = "x";
const char c[1] = "";
const char *const p = a;
p = b; // error, p is const, so any assignment to it is invalid
++*p; // error, p points to const char, so we cannot write through p to change the underlying data, even though ++a[0] would be legal
p = c; // error, p is const |
pjp wrote: | I can change it with a new assignment (no errors with -Wall): Code: | const char *foo = "foo";
|
| This causes foo to point somewhere different. It has no effect on the bytes that foo previously pointed at. pjp wrote: | But not using array indexing: Code: | strconst.c: In function ‘main’:
strconst.c:17:20: error: assignment of read-only location ‘*(foo + (sizetype)i)’
17 | foo[i] = foo[i] - 65; | My first thought was that 'foo = bar' would use a new memory location, but that didn't appear to happen during a small number of tests. What is going on that one change to a read-only location is okay, but the other is not? | See above: it depends on which location is read-only: the pointer, what it points at, or both. pjp wrote: | 12.7 String Constants (gnu.org) doesn't really help much, except the last paragraph. Although I think by "string constant" it means a string literal, not a 'const char *'? | Yes. pjp wrote: | Unfortunately I'm not yet able to distill the practical meaning of 'restrict' at cppreference, the use of which is specified in strtol, strcpy, and memcpy. I thought perhaps that might have helped.
https://en.cppreference.com/w/c/language/restrict | No, that is unrelated. You can ignore that for now. restrict deals with letting the optimizer make more assumptions about how writes through one pointer may impact reads from other pointers. |
|
Back to top |
|
 |
GDH-gentoo Veteran


Joined: 20 Jul 2019 Posts: 1857 Location: South America
|
Posted: Wed Apr 23, 2025 9:04 pm Post subject: |
|
|
Also, just in case because previous posts make me unsure if this is clear.
pjp wrote: | Hu wrote: | Writing const char *foo = "text" would be safer, as it prohibits later trying to write through foo into the underlying buffer. | Would you mind elaborating on this point, or possibly directing me to something that explains what's happening? I can change it with a new assignment (no errors with -Wall): Code: | const char *foo = "foo";
foo="bar"; | But not using array indexing: Code: | strconst.c: In function ‘main’:
strconst.c:17:20: error: assignment of read-only location ‘*(foo + (sizetype)i)’
17 | foo[i] = foo[i] - 65; |
|
foo, or more precisely, the object that identifier foo in the left hand of the assignments refers to, string literal "foo" and string literal "bar" are three different 'entities' in the program's memory (a. k. a. "objects").
The first assignment modifies the first object (by making it point elsewhere, as Hu explained), the second assignment has an indirection (because of "[" and "]") and attempts to modify (presumably, no code shown) one of the latter objects through a pointer value stored elsewhere —and fails because of the const qualification—.
Unlike other languages, in C (and C++) indexing is a pointer indirection in disguise.
EDIT: To break it down to subatomic particles
pjp wrote: | [...] what char *foo = "Some text here" is. |
It is a declaration with an initializer. This declaration:
- Defines an object (a 'thing' in memory) with certain properties. These properties make it suitable for storing values of pointer type.
- Associates an identifier, foo, with said object.
- Initializes the object with a value. The program can later change the value stored in the object.
When used in an expression, identifier foo:
- Is an expression that refers to the object defined by that declaration (an lvalue).
- Is an expression that has type "pointer to char". Not array type, not "string type" (there is no such thing in C).
The value that this object is initialized with makes it point to the first element of the string literal "Some text here", which is a different object. This other object has a sequence of elements that can store values of type "char" (numbers). Its first element stores the value that represents the charachter with glyph "S" using the encoding of the basic execution character set. _________________
NeddySeagoon wrote: | I'm not a witch, I'm a retired electronics engineer  |
Ionen wrote: | As a packager I just don't want things to get messier with weird build systems and multiple toolchains requirements though  |
|
|
Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|