我是初学者,我正在学习C语言。 我已经研究了数组,我知道数组的名称是第一个元素的地址,而数组的地址对应于数组描述的整个结构。
现在我正在研究结构,我想在这种情况下理解什么与结构的名称完全对应。 这些说明的输出结果:
#include <stdio.h>
struct numbers
{
int b;
int c;
};
int main(void)
{
struct numbers some_numbers = {1, 0};
printf("%d\n", some_numbers);
}
以下是:
Output: 1
输出这些指令的结果是:
#include <stdio.h>
struct numbers
{
char a;
int b;
int c;
};
int main(void)
{
struct numbers some_numbers = {0, 0, 0};
printf("%d\n", some_numbers);
}
是以下
Output: 7356928
结构的名称和第一个元素之间是否有任何联系,就像数组一样?
结构的名称应该是重要的,否则为什么我们要使用结构的名称作为函数的参数,如果我们想通过值传递结构?
答案 0 :(得分:4)
如果您将int
以外的任何内容传递给printf("%d")
,则会调用未定义的行为。
答案 1 :(得分:3)
就C标准是一致的,你正在调用undefined behaivor,因为你正在将结构传递给printf
,而%d
格式说明符期待int
}。
话虽如此,这是你特定情况下最有可能发生的事情。
在第一段代码中,struct包含int
作为第一个成员。假设在调用printf
时将结构的全部内容压入堆栈,%d
格式说明符将获取第一个int
成员并打印它。
在第二种情况下,第一个成员有char
,第二个成员有int
。因为成员通常在字节边界上对齐,这是成员大小的倍数,所以插入了额外的填充。使用隐式填充,struct可能看起来像这样,假设有一个4字节int
:
struct numbers
{
char a;
char padding[3];
int b;
int c;
};
初始化此结构时,每个成员都被填充,但填充的内容是不确定的。
然后将结构传递给printf
(假设整个结构被推送到堆栈上),%d
格式说明符将前4个字节读作int
。它由字段a
组成,它是char
,加上3个填充字节。您看到的输出反映了这些填充字节中的不确定值。
但重申一下,这是未定义的行为。使用不同的编译器或使用不同的优化设置进行编译可以改变未定义行为的显示方式。
答案 2 :(得分:2)
在具有罕见异常的表达式中使用的数组指示符将转换为指向其第一个元素的指针。
因此,当您将数组传递给函数时,实际上您将指针传递给数组的第一个元素。
至于结构,则没有这种隐式转换。将结构传递给函数时,将传递整个结构对象。
考虑到结构地址和结构的第一个数据成员的地址是一致的。
因此在这次电话会议中
printf("%d\n", some_numbers);
函数printf将传递给函数的内存解释为int类型对象占用的内存,实际上在第一个程序中,内存的初始部分被具有该类型的struture的第一个数据成员占用int
。
在第二种情况下,具有char类型的结构的第一个数据成员按字节填充,以使结构至少与int类型的对齐方式对齐。
在此初始化
中struct numbers some_numbers = {0, 0, 0};
仅初始化分配给结构的第一个成员的内存的一个字节。填充字节具有不确定的值。
结果,函数printf的相应调用具有不可预测和未定义的行为。
一般来说,这两个程序都没有意义并且有不确定的行为。
答案 3 :(得分:0)
阵列和结构与场景完全不同。结构是用户定义类型而不是数组。两者都有自己的访问机制。在内部结构中,您可以声明不同变量的结束编号,包括另一个结构的对象。
您在示例中所做的事情(在C中)根本不正确。但是在运算符重载的帮助下,你可以用C ++做。
答案 4 :(得分:0)
在printf()内部,您使用%d或%s等格式说明符。唯一的问题是:说明符应该与作为下一个参数传递的数据匹配。
因此,一旦你把不一致的说明符和数据对,你应该收到任何东西,并且由于不同数据类型的不兼容内存布局,它们中的大多数都可能是垃圾。