mirror of
https://github.com/google/pebble.git
synced 2025-03-20 11:01:20 +00:00
190 lines
6 KiB
Markdown
190 lines
6 KiB
Markdown
|
---
|
||
|
# Copyright 2025 Google LLC
|
||
|
#
|
||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
# you may not use this file except in compliance with the License.
|
||
|
# You may obtain a copy of the License at
|
||
|
#
|
||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||
|
#
|
||
|
# Unless required by applicable law or agreed to in writing, software
|
||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
# See the License for the specific language governing permissions and
|
||
|
# limitations under the License.
|
||
|
|
||
|
title: Common Syntax Errors
|
||
|
description: |
|
||
|
Details of common problems encountered when writing C apps for Pebble, and how
|
||
|
to resolve them.
|
||
|
guide_group: debugging
|
||
|
order: 2
|
||
|
---
|
||
|
|
||
|
If a developer is relatively new to writing Pebble apps (or new to the C
|
||
|
language in general), there may be times when problems with an app's code will
|
||
|
cause compilation errors. Some types of errors with the code itself can be
|
||
|
detected by the compiler and this helps reduce the number that cause problems
|
||
|
when the code is run on Pebble.
|
||
|
|
||
|
These are problems with how app code is written, as opposed to runtime errors
|
||
|
(discussed in {% guide_link debugging/common-runtime-errors %}), which may
|
||
|
include breaking the rules of the C language or bad practices that the compiler
|
||
|
is able to detect and show as an error. The following are some examples.
|
||
|
|
||
|
|
||
|
### Undeclared Variables
|
||
|
|
||
|
This error means that a variable that has been referenced is not available in
|
||
|
the current scope.
|
||
|
|
||
|
```nc|text
|
||
|
../src/main.c: In function 'toggle_logging':
|
||
|
../src/main.c:33:6: error: 'is_now_logging' undeclared (first use in this function)
|
||
|
if(is_now_logging == true) {
|
||
|
^
|
||
|
```
|
||
|
|
||
|
In the above example, the symbol `is_now_logging` has been used in the
|
||
|
`toggle_logging` function, but it was not first declared there. This could be
|
||
|
because the declaring line has been deleted, or it was expected to be available
|
||
|
globally, but isn't.
|
||
|
|
||
|
To fix this, consider where else the symbol is required. If it is needed in
|
||
|
other functions, move the declaration to a global scope (outside any function).
|
||
|
If it is needed only for this function, declare it before the offending line
|
||
|
(here line `33`).
|
||
|
|
||
|
|
||
|
### Undeclared Functions
|
||
|
|
||
|
Another variant of the above problem can occur when declaring new functions in a
|
||
|
code file. Due to the nature of C compilation, any function a
|
||
|
developer attempts to call must have been previously encountered by the compiler
|
||
|
in order to be visible. This can be done through
|
||
|
[forward declaration](http://en.wikipedia.org/wiki/Forward_declaration).
|
||
|
|
||
|
For example, the code segment below will not compile:
|
||
|
|
||
|
```c
|
||
|
static void window_load(Window *window) {
|
||
|
my_function();
|
||
|
}
|
||
|
|
||
|
void my_function() {
|
||
|
// Some code here
|
||
|
|
||
|
}
|
||
|
```
|
||
|
|
||
|
The compiler will report this with an 'implicit declaration' error, as the app
|
||
|
has implied the function's existence by calling it, even though the compiler has
|
||
|
not seen it previously:
|
||
|
|
||
|
```nc|text
|
||
|
../src/function-visibility.c: In function 'window_load':
|
||
|
../src/function-visibility.c:6:3: error: implicit declaration of function 'my_function' [-Werror=implicit-function-declaration]
|
||
|
my_function();
|
||
|
^
|
||
|
```
|
||
|
|
||
|
This is because the *declaration* of `my_function()` occurs after it is called
|
||
|
in `window_load()`. There are two options to fix this.
|
||
|
|
||
|
* Move the function declaration above any calls to it, so it has been
|
||
|
encountered by the compiler:
|
||
|
|
||
|
```c
|
||
|
void my_function() {
|
||
|
// Some code here
|
||
|
|
||
|
}
|
||
|
|
||
|
static void window_load(Window *window) {
|
||
|
my_function();
|
||
|
}
|
||
|
```
|
||
|
|
||
|
* Declare the function by prototype before it is called, and provide the
|
||
|
implementation later:
|
||
|
|
||
|
```c
|
||
|
void my_function();
|
||
|
|
||
|
static void window_load(Window *window) {
|
||
|
my_function();
|
||
|
}
|
||
|
|
||
|
void my_function() {
|
||
|
// Some code here
|
||
|
|
||
|
}
|
||
|
```
|
||
|
|
||
|
|
||
|
### Too Few Arguments
|
||
|
|
||
|
When creating functions with argument lists, sometimes the requirements of the
|
||
|
function change and the developer forgets to update the places where it is
|
||
|
called.
|
||
|
|
||
|
```nc|text
|
||
|
../src/main.c: In function 'select_click_handler':
|
||
|
../src/main.c:57:3: error: too few arguments to function 'toggle_logging'
|
||
|
toggle_logging();
|
||
|
^
|
||
|
../src/main.c:32:13: note: declared here
|
||
|
static void toggle_logging(bool will_log) {
|
||
|
^
|
||
|
```
|
||
|
|
||
|
The example above reports that the app tried to call the `toggle_logging()`
|
||
|
function in `select_click_handler()` on line 57, but did not supply enough
|
||
|
arguments. The argument list expected in the function definition is shown in the
|
||
|
second part of the output message, which here exists on line 32 and expects an
|
||
|
extra value of type `bool`.
|
||
|
|
||
|
To fix this, establish which version of the function is required, and update
|
||
|
either the calls or the declaration to match.
|
||
|
|
||
|
|
||
|
### Incorrect Callback Implementations
|
||
|
|
||
|
In the Pebble SDK there are many instances where the developer must implement a
|
||
|
function signature required for callbacks, such as for a ``WindowHandlers``
|
||
|
object. This means that when implementing the handler the developer-defined
|
||
|
callback must match the return type and argument list specified in the API
|
||
|
documentation.
|
||
|
|
||
|
For example, the ``WindowHandler`` callback (used for the `load` and `unload`
|
||
|
events in a ``Window``'s lifecycle) has the following signature:
|
||
|
|
||
|
```c
|
||
|
typedef void(* WindowHandler)(struct Window *window)
|
||
|
```
|
||
|
|
||
|
This specifies a return type of `void` and a single argument: a pointer of type
|
||
|
``Window``. Therefore the implemented callback should look like this:
|
||
|
|
||
|
```c
|
||
|
void window_load(Window *window) {
|
||
|
|
||
|
}
|
||
|
```
|
||
|
|
||
|
If the developer does not specify the correct return type and argument list in
|
||
|
their callback implementation, the compiler will let them know with an error
|
||
|
like the following, stating that the type of function passed by the developer
|
||
|
does not match that which is expected:
|
||
|
|
||
|
```nc|text
|
||
|
../src/main.c: In function 'init':
|
||
|
../src/main.c:82:5: error: initialization from incompatible pointer type [-Werror]
|
||
|
.load = main_window_load,
|
||
|
^
|
||
|
../src/main.c:82:5: error: (near initialization for '(anonymous).load') [-Werror]
|
||
|
```
|
||
|
|
||
|
To fix this, double check that the implementation provided has the same return
|
||
|
type and argument list as specified in the API documentation.
|