代码块作用域:在代码中定义的变量具有代码块作用域。
文件作用域:一个在所有函数之外定义的变量具有文件作用域。
函数原型作用域:
函数作用域:
外部链接(external linkage):
内部链接(internal linkage):
空链接(no linkage): 具有代码块作用域或者函数原型作用域的变量有空链接。
int giants = 5; //文件作用域,外部链接
static int dodgers = 3; //文件作用域,内部链接
int main()
{
}
静态存储时期:如果一个变量具有静态存储时期,它在程序执行期间将一直存在。
自动存储时期:
存储类 | 时期 | 作用域 | 链接 | 声明方式 |
自动 | 自动 | 代码块 | 空 | 代码块内 |
寄存器 | 自动 | 代码块 | 空 | 代码块内,只用关键字register |
具有外部链接的静态 | 静态 | 文件 | 外部 | 所有函数之外 |
具有内部链接的静态 | 静态 | 文件 | 内部 | 所有函数之外,使用关键字static |
空连接的静态 | 静态 | 代码块 | 空 | 代码块内,使用关键字static |
自动变量不会自动初始化,
int main()
{
int repid;
int tents = 5;
}
tents 初始化为5, 而repid是任意值。
寄存器变量多是存放在一个寄存器而非内存中,所以无法获得寄存器变量的地址。
register 声明一个寄存器变量仅是一个请求,而非一条直接命令。 所以,变量有可能只是一个普通的自动变量,然而,您依然不能对它使用 地址运算符。
外部变量会自动初始化为零。
只可以使用常量表达式来初始化文件作用域变量。
int tern = 1; //定义声明
extern int tern; //引用声明
const float * pf; //指向一个常量浮点数值
float const * pf; //指向一个常量浮点数值
float * const pf; //pf必须总是指向同一个地址。
/* file1.c */
const double PI = 3.141592;
/* file2.c */
extern const double PI;
/* constant.h */
static const double PI = 3.141592; //不加static会出现重定义
/* file1.c */
#include "constant.h"
/* file2.c */
#include "constant.h"
/* constant.c */
#include "constant.h"
const double PI = 3.141592;
/* constant.h */
extern const double PI;
/* file1.c */
#include "constant.h"
/* file2.c */
#include "constant.h"
字符串是以空字符 \0 结尾的char数组。
如果字符串文字中间没有间隔或者间隔是空格,C语言会将其串联起来。下面两个是等价的。
char greeting[50] = "Hello, and " "how are " "you " "today!";
char greeting[50] = "Hello, and how are you today!";
字符串常量属于静态存储。静态存储是指如果在一个函数中使用字符串常量, 即使是多次调用了这个函数,该字符串在程序的整个运行过程中只存储一份。 整个引号中的内容作为指向该字符串存储位置的指针。
const char m1[40] = “Limit yourself”;
字符数组名也是数组首元素的地址。
m1 == &m1[0]
*m1 == ‘L’
*(m1+1) == m1[1] == ‘i’
char heart[] = “I Love you”;
char * head = “I Love you”;
heart是个常量,head是个变量。
都是在静态存储区为字符串分配空间,heart表示的就是第一个字节的地址, 而系统还需要为head分配一个指针的存储位置。
数组的初始化是从静态存储区把一个字符串复制给数组, 而指针的初始化只是复制字符串的地址。
const char * mytal[5] = {“Adding numbers”, “huang jian”};
常量数组
const int days[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
数组的初始化
- 如果不初始化数组,数组的每个元素都是无用的数值。
- 部分初始化数组,那么未初始化的元素被设置为零。
int arr[10]; 未初始化
int arr[10] = {100, 200}; a[0]=100, a[1]=200, 其它的都是零
int arr[10] = {0}; 整个数组都是零
sizeof 计算数组中元素的数目。
const int days[] = {31,28,31,30,31,30,31,31,30,31,30,31};
int nums = sizeof days / sizeof days[0];
sizeof 给出其后的对象或类型的大小(以字节为单位)。
float rain[5][12];
rain具有5个元素,并且每个元素都是包含12个float数值的数组。
rain[0] 是包含12个float元素的数组。
rain[0][0] 是一个float数。
数组名==数组首元素的地址
int zippo[5][2];
int (*pz)[2];
pz = zippo;
zippo == &zippo[0]
zippo[0] == &zippo[0][0]
zippo[m[n] = *(*(zippo+m)+n)
pz[m[n] = *(*(pz+m)+n)
zippo == &zippo[0]
zippo+2 == &zippo[2]
*(zippo+2) == zippo[2]
arr[n]的意思是 *(arr+n),即寻址到内存中的arr,然后移动n个单位,再取出值。
指针Tips:
指针的数值就是它所指的对象的地址。对于包含n个字节的数据类型,对象的地址通常指的是其首字节的地址。
在指针前用运算符星号就可以得到该指针所指向的对象的值。
对指针加1,等价于对指针的值加上它指向的对象的字节大小。
int sum(int * ar, int n);
int sum(int ar[], int n);
在这里,int ar[] 也是表示ar是指向int的指针。
int sum(const int ar[], int n);
加上const,在该函数中则不能修改指针ar指向的内容。
void fun(int (*pt)[4]);
void fun(int pt[][4]);
typedef 数组
typedef int arr4[4]; //arr4是4个int的数组。
typedef arr4 arr3x4[3]; //arr3x4是3个arr4数组
int sum2(arr3x4 ar, int rows);
int sum2(int ar[3][4], int rows); //这里的3会被自动忽略,不起作用
int sum2(int ar[][4], int rows);
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "list.h"
#include "supporting_functions.h"
void vTask1(void * pvParameters);
void vTask2(void * pvParameters);
TaskHandle_t xTask2Handle;
int main()
{
xTaskCreate(vTask1, "Task 1", 1000, NULL, 2, NULL);
xTaskCreate(vTask2, "Task 2", 1000, NULL, 1, &xTask2Handle);
vTaskStartScheduler();
for (;;);
return 0;
}
void vTask1(void * pvParameters)
{
UBaseType_t uxPriority = uxTaskPriorityGet(NULL);
for (;;)
{
vPrintString("Task1 is running\n");
vPrintString("About to raise the Task2 priority\n");
vTaskPrioritySet(xTask2Handle, (uxPriority + 1));
}
}
void vTask2(void * pvParameters)
{
UBaseType_t uxPriority = uxTaskPriorityGet(NULL);
for (;;)
{
vPrintString("Task2 is running\n");
vPrintString("About to lower the Task2 priority\n");
vTaskPrioritySet(NULL, (uxPriority - 2));
}
}
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "list.h"
#include "supporting_functions.h"
#define mainDELAY_LOOP_COUNT (0xffffff)
void vContinuousProcessingTask(void * pvParameters);
void vPeriodicTask(void * pvParameters);
const char * pcTextForTask1 = "Continuous task 1 is running\n";
const char * pcTextForTask2 = "Continuous task 2 is running\n";
const char * pcTextForPeriodicTask = "Periodic task is running\n";
int main(void)
{
xTaskCreate(vContinuousProcessingTask, "Task 1", 1000, (void*)pcTextForTask1, 1, NULL);
xTaskCreate(vContinuousProcessingTask, "Task 2", 1000, (void*)pcTextForTask2, 1, NULL);
xTaskCreate(vPeriodicTask, "Task 3", 1000, (void*)pcTextForPeriodicTask, 2, NULL);
vTaskStartScheduler();
for (;;);
return 0;
}
void vContinuousProcessingTask(void * pvParameters)
{
char * pcTaskName = (char*)pvParameters;
for (;;)
{
vPrintString(pcTaskName);
}
}
void vPeriodicTask(void * pvParameters)
{
const TickType_t xDelay250ms = pdMS_TO_TICKS(250UL);
TickType_t xLastWakeTime = xTaskGetTickCount();
for (;;)
{
vPrintString("Periodic task is running\n");
vTaskDelayUntil(&xLastWakeTime, xDelay250ms);
}
}
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "list.h"
#include "supporting_functions.h"
void vTaskFunction(void * pvParameters);
static uint32_t ulIdleCycleCount = 0UL;
const char * pcTextForTask1 = "Task 1 is running\n";
const char * pcTextForTask2 = "Task 2 is running\n";
int main()
{
xTaskCreate(vTaskFunction, "Task 1", 1000, (void*)pcTextForTask1, 1, NULL);
xTaskCreate(vTaskFunction, "Task 2", 1000, (void*)pcTextForTask2, 2, NULL);
vTaskStartScheduler();
for (;;);
return 0;
}
void vTaskFunction(void * pvParameters)
{
char * pcTaskName = (char*)pvParameters;
const TickType_t xDelay250ms = pdMS_TO_TICKS(250UL);
for (;;)
{
vPrintStringAndNumber(pcTaskName, ulIdleCycleCount);
vTaskDelay(xDelay250ms);
}
}
void vApplicationIdleHook(void)
{
ulIdleCycleCount++;
}
FreeRTOSConfig.h
#define configUSE_IDLE_HOOK 1