打印返回结构的成员

时间:2011-11-01 08:00:20

标签: c arrays struct return-value lvalue

我在打印从函数返回的结构的成员时遇到问题:

#include <stdio.h>

struct hex_string
{
    char a[9];
};

struct hex_string to_hex_string_(unsigned x)
{
    static const char hex_digits[] = "0123456789ABCDEF";
    struct hex_string result;
    char * p = result.a;
    int i;
    for (i = 28; i >= 0; i -= 4)
    {
        *p++ = hex_digits[(x >> i) & 15];
    }
    *p = 0;
    printf("%s\n", result.a);   /* works */
    return result;
}

void test_hex(void)
{
    printf("%s\n", to_hex_string_(12345).a);   /* crashes */
}

printf内的to_hex_string_调用会打印出正确的结果,但printf内的test_hex调用会导致我的程序崩溃。究竟是为什么呢?这是一生的问题,还是其他问题?

当我用printf替换puts(to_hex_string_(12345).a)调用时,出现编译错误:

invalid use of non-lvalue array

这里发生了什么?

3 个答案:

答案 0 :(得分:18)

C中有一条很少生效的规则,其中规定:

  

如果尝试修改函数调用的结果或者   在下一个序列点之后访问它,行为是未定义的。 (C99§6.5.2.2)

在这种情况下,在printf()的参数被评估之后,printf()函数本身执行之前,有一个序列点。传递给printf()的指针是指向返回值本身的元素的指针 - 当printf()尝试通过该指针访问字符串时,您会崩溃。

这个问题很难遇到,因为函数值不是左值,所以你不能用&直接指向它。

答案 1 :(得分:13)

你已经设法遇到了一个相当模糊的语言角落。

在大多数情况下,数组类型的表达式被隐式转换为指向数组第一个元素的指针;例外情况是表达式是一元&运算符的操作数,当它是一元sizeof运算符的操作数时,以及它是用于初始化数组对象的初始值设定项中的字符串文字。这些例外都不适用于此。

但是在转换中有一个隐含的假设:指针指向数组的第一个元素 object

大多数数组表达式 - 实际上几乎所有数组 - 都引用了一些数组对象,例如声明的数组变量,多维数组的元素等等。函数不能返回数组,因此无法以这种方式获得非左值数组表达式。

但正如您所见,函数可以返回包含数组的结构 - 并且没有与数组表达式to_hex_string_(12345).a关联的对象。

新的ISO C11标准通过在描述存储持续时间的部分中添加新措辞来解决此问题。 The N1570 draft,第6.2.4p8节,说:

  

具有结构或联合类型的非左值表达式,其中   结构或联合包含一个数组类型的成员(包括,   递归地,所有包含的结构和联合的成员)指的是   具有自动存储持续时间和临时生存期的对象。   它的生命周期从评估表达式及其初始值开始   value是表达式的值。它的生命终结了   对包含完整表达式或完整声明符的评估结束。   任何使用临时生命周期修改对象的尝试都会导致   未定义的行为。

实际上,这表示函数的返回值(与大多数函数结果不同)是临时对象的值,允许其数组成员的衰减为您提供(暂时)有效指针。

但是直到编译器完全支持新的C标准(这将不会持续几年),你只需要避免引用返回结构的数组成员。

答案 2 :(得分:-1)

您遇到的问题是:返回的变量result是函数 _to_hex_string 的局部变量,这意味着它在函数调用结束时被删除。因此,当您尝试在函数test_hex中检查它时,它将不再可用。

要解决您的问题,您可以处理指针。

这是您的代码修改

struct hex_string
{
    char a[9];
};

struct hex_string * to_hex_string_(unsigned x) // here you return a pointer
{
    static const char hex_digits[] = "0123456789ABCDEF";
    struct hex_string result;

    result = (struct hex_string *) malloc(sizeof(struct hex_string));
    char * p = result->a;
    int i;

    for (i = 28; i >= 0; i -= 4)
    {
        *p++ = hex_digits[(x >> i) & 15];
    }

    *p = 0;
    printf("%s\n", result->a);   /* works */
    return result;
}

void test_hex(void)
{
    printf("%s\n", to_hex_string_(12345)->a);  /* works */
}

我度过了愉快的一天