我正在使用Keil C51编译器来编程8051微控制器 . 由于某些原因,我的代码没有运行 - 我设法追踪错误,但我仍然难以理解它 . 为什么第一个代码与另一个代码相比是错误的?值得注意的是,编译器没有抛出任何错误,代码甚至没有在微控制器上启动 .
错误的代码:
file1.h
extern STRUCT_TYPEDEF array_var[];
file2.c
// Global variable initialization
STRUCT_TYPEDEF array_var[] = some_struct.array2_var;
将这些更改为:
file1.h
extern STRUCT_TYPEDEF *array_var;
file2.c
// Global variable initialization
STRUCT_TYPEDEF *array_var = &some_struct.array2_var[0];
它开始工作了 .
此外,这部分代码仅在类似“array_var [0] .property = ...”的函数中引用,但这些函数都没有从应用程序中调用过 .
some_struct变量在另一个模块中声明 .
它为什么会这样? []和*之间有什么区别我不知道吗?
EDIT1: 据说指针和数组是不同的东西......但是,"[]"语法与"*"有什么不同?我认为只要方括号为空(例如函数参数),编译器就会将其转换为指针 . 我还认为提供一个数组会导致给我第一个元素的地址 .
现在,每个人都在说指针和数组是不同的 - 但我找不到任何关于它们究竟有什么不同的信息 . 当我将数组作为rvalue而不是指向其第一个元素的指针时,编译器如何看待它?
2 回答
不是在声明中初始化数组的有效方法 . 数组初始值设定项必须是大括号括起来的初始值设定项列表,例如
您不能使用另一个array1初始化数组,也不能以这种方式将一个数组分配给另一个数组:
如果要将
some_struct.array2_var
的内容复制到array_var
,则必须使用类似memcpy
的库函数:您还必须声明
array_var
的大小;你可以轻松地做到:如果您不知道它需要多大,那么如果它需要在文件范围或者具有
static
存储持续时间,那么你可以工作,或者你可以动态地声明内存:这都假定
some_struct.array2_var
是一个声明为的数组如果它也只是一个指针,那么你将不得不以其他方式跟踪数组大小 .
EDIT
如果您希望
array_var
只是指向some_struct.array2_var
的第一个元素,那么您将执行以下操作:除非它是
sizeof
或一元&
运算符的操作数,否则表达式为“N元素数组T
" will be converted ("衰变") to an expression of type "指向T
”,表达式的值将是数组的第一个元素的地址 . 上面的代码完全等同于字符串文字除外,例如char message [] =“Hello”;;字符串文字“Hello”是一个数组表达式,但该语言将其视为一种特殊情况 .
这个 ...
...是一个未知大小和外部链接的数组的声明 . 因为未指定大小,所以该声明将
array_var
留下"incomplete type";除非其类型由同一翻译单元中的另一个声明完成,否则会阻止对该变量的某些使用 . 例如,它不能是sizeof
运算符的操作数 .这个 ...
...由于提供了初始化程序,声称是
array_var
的定义 . 但是, The initializer is not of the correct form for a variable of array type . 数组初始值设定项由一个或多个数组元素的逗号分隔序列组成,在强制花括号内({}
) . 正如C不支持全数组赋值一样,它不支持数组值作为数组初始值设定项 .相比之下,这......
...是具有外部链接的指针的声明 . 它有一个完整的类型 . 还有这个 ...
...是变量的有效定义,具有合适的初始化程序 . 因为数组值在这个上下文中衰减为指针,就像大多数(但不是全部)其他指针一样,它等同于:
在将其与原始代码进行比较时,必须理解尽管它们具有紧密关联,但指针和数组是完全独立的类型 .
是否正常访问变量与编译器是否愿意接受代码无关 .
显然是这样,因为这个问题似乎假设没有区别 .
这两种形式可以互换使用,用于声明功能参数 . 在该上下文中,都将参数声明为指针 . 这是一种符号和代码清晰度方便,因为作为函数参数出现的数组值会衰减到指针 . 您永远不能将数组作为函数参数实际传递 - 当参数指定数组时,将传递指针 .
然而,如上所述,这两种形式不等同于声明普通变量 .