打印返回的结构体的成员

发布于 2024-12-12 17:59:45 字数 877 浏览 3 评论 0原文

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

#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 */
}

to_hex_string_ 内的 printf 调用打印正确的结果,但 printf code> 在 test_hex 内调用使我的程序崩溃。到底是为什么呢?是一生的问题还是其他什么问题?

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

invalid use of non-lvalue array

这是怎么回事?

I'm having trouble printing a member of a struct that is returned from a function:

#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 */
}

The printf call inside to_hex_string_ prints the correct result, but the printf call inside test_hex crashes my program. Why exactly is that? Is it a lifetime issue, or is it something else?

When I replace the printf call with puts(to_hex_string_(12345).a), I get a compiler error:

invalid use of non-lvalue array

What's going on here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦冥 2024-12-19 17:59:45

C 中有一条很少生效的规则,它指出:

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

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

这个问题很难遇到,因为函数值不是左值,因此您不能直接使用 & 获取指向它的指针。

There is a rule in C which seldom comes into effect, which states:

If an attempt is made to modify the result of a function call or to
access it after the next sequence point, the behavior is undefined. (C99 §6.5.2.2)

In this case, there is a sequence point after the arguments to printf() are evaluated and before the printf() function itself executes. The pointer you pass to printf() is a pointer to an element of the return value itself - and when printf() tries to access the string through that pointer, you get your crash.

This issue is hard to run into, because a function value isn't an lvalue so you can't directly take a pointer to it with &.

饭团 2024-12-19 17:59:45

您已经成功地遇到了该语言的一个相当晦涩的角落案例。

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

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

大多数数组表达式(实际上几乎所有数组表达式)都引用某个数组对象,例如声明的数组变量、多维数组的元素等等。函数无法返回数组,因此您无法以这种方式获取非左值数组表达式。

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

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

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

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

但是,在编译器完全支持新的 C 标准(几年后)之前,您只需避免引用返回结构的数组成员即可。

You've managed to run into a fairly obscure corner case of the language.

An expression of array type, in most contexts, is implicitly converted to a pointer to the first element of the array; the exceptions are when the expression is the operand of a unary & operator, when it's the operand of a unary sizeof operator, and when it's a string literal in an initializer used to initialize an array object. None of these exceptions applies here.

But there's an implicit assumption in that conversion: the pointer is to the first element of the array object.

Most array expressions -- almost all of them, in fact -- refer to some array object, such as a declared array variable, an element of a multidimensional array, and so forth. Functions can't return arrays, so you can't get a non-lvalue array expression that way.

But as you've seen, a function can return a struct that contains an array -- and there's no object associated with the array expression to_hex_string_(12345).a.

The new ISO C11 standard addresses this by adding new wording to the section describing storage durations. The N1570 draft, section 6.2.4p8, says:

A non-lvalue expression with structure or union type, where the
structure or union contains a member with array type (including,
recursively, members of all contained structures and unions) refers to
an object with automatic storage duration and temporary lifetime.
Its lifetime begins when the expression is evaluated and its initial
value is the value of the expression. Its lifetime ends when the
evaluation of the containing full expression or full declarator ends.
Any attempt to modify an object with temporary lifetime results in
undefined behavior.

In effect, this says that the returned value from your function (unlike most function results) is the value of a temporary object, allowing the decay of its array member to give you a (temporarily) valid pointer.

But until compilers fully support the new C standard (which won't be for some years), you'll just have to avoid referring to array members of returned structures.

夏日浅笑〃 2024-12-19 17:59:45

您面临的问题是:返回的变量 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 */
}

今天过得愉快吗

The problem you're facing is that : the variable result which is return is a local variable of the function _to_hex_string, that's means it is deleted at the end of the fonction call. so when you try to check it in the fonction test_hex it is no available any more.

To solve your problem you can deal with pointer.

here is your code modify

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 */
}

Have I nice day

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文