tweaks to C notes
This commit is contained in:
parent
9dcae3ac16
commit
f471f891e0
3 changed files with 52 additions and 35 deletions
|
|
@ -60,30 +60,17 @@ In memory this would actually be:
|
|||
With each char corresponding to an ASCII number apart from the null which would
|
||||
just be `0000 0000`.
|
||||
|
||||
### String literals
|
||||
|
||||
The easiest way to declare a string as a `char` array is to use the format we've
|
||||
already used which is string literal notation:
|
||||
|
||||
```c
|
||||
char word[] = "Hello";
|
||||
```
|
||||
|
||||
The null terminator is implied in this form, you do not need to add it manually.
|
||||
Also the length is fixed to the length of the string (in this case `6` for the
|
||||
five actual characters plus the null).
|
||||
|
||||
### Non-literal string declaration
|
||||
|
||||
The more formal way of doing this would be:
|
||||
|
||||
```c
|
||||
char word[6] = {'H', 'e', 'l', 'l', 'o', '\0'}
|
||||
```
|
||||
|
||||
However, in practice, if you just want quick access to a string, where you don't
|
||||
need to modify the individual characters later, you can just use a direct
|
||||
pointer definition:
|
||||
### String literals
|
||||
|
||||
In practice, if you just want quick access to a string, where you don't need to
|
||||
modify the individual characters later, you can just use a direct pointer
|
||||
definition:
|
||||
|
||||
```c
|
||||
char *name = "Thomas";
|
||||
|
|
@ -94,3 +81,15 @@ is a string literal and is stored as read-only. It can be redefined (the pointer
|
|||
can point to something else) but it's not mutable itself.
|
||||
|
||||
More info in [Pointers in C](./Pointers_in_C.md).
|
||||
|
||||
Note that the `*` in the declaration is part of the type definition, it's
|
||||
signalling that its a pointer to a string literal, it's not
|
||||
referencing/dereferencing or doing anything to the bytes.
|
||||
|
||||
Technically you could write:
|
||||
|
||||
```c
|
||||
char* name = "Thomas"
|
||||
```
|
||||
|
||||
This would be clearer but it is not the convention.
|
||||
|
|
|
|||
|
|
@ -3,14 +3,35 @@ tags:
|
|||
- C
|
||||
---
|
||||
|
||||
Think of them as a find and replace that takes place before compilation.
|
||||
Think of macros as a find and replace that takes place before compilation at the
|
||||
[pre-processor](./C_compilation_process.md) stage.
|
||||
|
||||
They are ephemeral and never make it into the compiled code.
|
||||
They are ephemeral and never make it into the compiled code in the form they are
|
||||
defined as.
|
||||
|
||||
With a macro, the computation happens "inline" without having to call functions
|
||||
which make costly alterations to the stack.
|
||||
When the preprocessor injects the value, the injection happens "inline" without
|
||||
having to call functions which make costly alterations to the stack, which is
|
||||
the main benefit - efficiency.
|
||||
|
||||
A function and function call such as:
|
||||
Starting with a simple example:
|
||||
|
||||
```c
|
||||
#define NAME "Thomas"
|
||||
```
|
||||
|
||||
This is not actually a variable because it has no memory address. It never makes
|
||||
it to memory-assignation because it doesn't exist after pre-processing. By the
|
||||
compilation stage,j this value has been added to the code as a type
|
||||
corresponding to the literal you defined; in this case a string literal
|
||||
(`char *`). To emphasise, the macro itself has no type because it doesn't exist
|
||||
at the type level (compilation), the data type it represents after injection is
|
||||
applied by the compiler through parsing.
|
||||
|
||||
> The convention is to have macros in `ALL_CAPS` to distinguish them from real
|
||||
> variables. Don't confuse them for constants, constants are actually written in
|
||||
> lowercase like other actual variables.
|
||||
|
||||
To use a more complex example, a function and function call such as:
|
||||
|
||||
```c
|
||||
int square(int x) { return x * x; }
|
||||
|
|
@ -32,7 +53,3 @@ int a = ((5) * (5));
|
|||
```
|
||||
|
||||
after pre-processing but before compilation.
|
||||
|
||||
## Syntax
|
||||
|
||||
`#define` always creates a macro but there are different types.
|
||||
|
|
|
|||
|
|
@ -48,13 +48,17 @@ char *name = "Thomas";
|
|||
```
|
||||
|
||||
Then to reference the value (_not_ the address, the actual value) you just use
|
||||
`name`.
|
||||
`name`. The `*` is just part of the type definition in the above - it's just
|
||||
signalling the type. If you later want to change the value, you then use `*` as
|
||||
an operator:
|
||||
|
||||
This is confusing but I just have to accept for now.
|
||||
```c
|
||||
*name = 'Tom';
|
||||
```
|
||||
|
||||
Note that if you do this, it creates the string in read-only memory. You can't
|
||||
modify the individual characters of `"Thomas"`. To do this you would need to
|
||||
define it as:
|
||||
Note that if you use a pointer to `char`, it creates the string in read-only
|
||||
memory. You can't modify the individual characters of `"Thomas"`. To do this you
|
||||
would need to define it as:
|
||||
|
||||
```c
|
||||
char name[] = "Thomas";
|
||||
|
|
@ -85,6 +89,3 @@ Or, using a variable:
|
|||
static char *topic = "test_topic";
|
||||
mqtt_publish(mqtt_client, topic, "Test message");
|
||||
```
|
||||
|
||||
> Note in the above the `*` is part of the type definition, _not_ the variable.
|
||||
> Even more confusing!
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue