AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 77054422
Accepted
user16217248
user16217248
Asked: 2023-09-07 02:26:24 +0800 CST2023-09-07 02:26:24 +0800 CST 2023-09-07 02:26:24 +0800 CST

Posso atribuir ou retornar uma estrutura com elementos não atribuídos em C?

  • 772

Em C, usar uma variável não inicializada é um comportamento indefinido. Incluindo:

int x;
int y = x;

No entanto, suponha que eu tenha o seguinte:

struct Struct {
    int a;
    int b;
};
struct Struct s;
s.a = 1;
struct Struct s0 = s;
return s; // Assuming an enclosing function with the correct return type

O código acima invoca um comportamento indefinido, no caso de alguns elementos, mas não todos, terem sido atribuídos?

c
  • 4 4 respostas
  • 76 Views

4 respostas

  • Voted
  1. Best Answer
    Eric Postpischil
    2023-09-07T05:31:00+08:002023-09-07T05:31:00+08:00

    Isto não é abordado adequadamente pelo padrão C, mas uma implementação C razoável suporta o uso de uma estrutura inteira quando alguns membros não são inicializados. E há uma solução simples para qualquer implementação C.

    Observe que “Em C, usar uma variável não inicializada é um comportamento indefinido” não é totalmente verdade. O valor de um objeto não inicializado com duração de armazenamento automático é indeterminado de acordo com C 2018 6.7.9 10. Usar o valor de tal objeto tem comportamento indefinido se seu endereço não for usado, de acordo com C 2018 6.3.2.1 2:

    … Se o lvalue designa um objeto de duração de armazenamento automático que poderia ter sido declarado com a registerclasse de armazenamento (nunca teve seu endereço obtido) e esse objeto não foi inicializado (não foi declarado com um inicializador e nenhuma atribuição a ele foi realizada antes de usar ), o comportamento é indefinido.

    Assim, para garantir que a utilização de uma estrutura não tenha comportamento indefinido, basta obter o seu endereço. Digamos que você tenha algum objeto de estrutura s. Então podemos pegar seu endereço (e descartá-lo) simplesmente inserindo (void) &s;o código. Ao obter seu endereço, evitamos que o objeto seja possivelmente declarado register, portanto 6.3.2.1 2 não se aplicará.

    Ainda pode haver alguma preocupação de que o uso de um objeto com valor indeterminado possa encontrar uma representação trap. No entanto, isso não ocorre para estruturas, conforme 6.2.6.1 2:

    … O valor de uma estrutura ou objeto de união nunca é uma representação de armadilha, mesmo que o valor de um membro da estrutura ou objeto de união possa ser uma representação de armadilha.

    Esse parágrafo nos diz que o comitê C pretendia que os programas C fossem capazes de usar estruturas inteiras, mesmo que seus membros não fossem todos inicializados. 6.3.2.1 2, sobre comportamento indefinido para alguns objetos não inicializados, foi adicionado posteriormente para fornecer um recurso da Hewlett-Packard que permite ao processador rastrear registros não inicializados. Quando essa adição foi feita, o comitê não adicionou uma declaração semelhante a 6.2.6.1 2, informando-nos que ela não se aplicaria a uma estrutura.

    Minha opinião seria que 6.2.6.1 2 indica que a intenção é que seja seguro copiar estruturas inteiras e 6.3.2.1 2 não pretende mudar isso. Porém, para ser totalmente seguro, tomar o endereço da estrutura conforme explicado acima garante que o acesso à estrutura não terá um comportamento indefinido, independentemente da interpretação do padrão a esse respeito.

    • 3
  2. Matt
    2023-09-07T05:18:15+08:002023-09-07T05:18:15+08:00

    A questão real e a questão pretendida parecem ser diferentes. Respondendo à pergunta real, a resposta curta é não, ele nem compila - portanto, não pode criar nenhum comportamento indefinido.

    Parece que a pergunta pretendida é: "o retorno de uma estrutura parcialmente atribuída causará um comportamento indefinido?" O retorno implica que isso está dentro de uma função, então talvez seja uma complicação indesejada, mas vamos pensar nisso por um momento e agrupar o código original da operação em uma função e alguns elementos extras (como um main) para pontos de discussão :

    #include <stdio.h>
    
    struct Struct {
        int a;
        int b;
    };
    
    struct Struct myfunc(void)
    {
        struct Struct s;
        s.a = 1;
        struct Struct s0 = s;
        return s;
    }
    
    void main(void)
    {
        struct Struct bob = myfunc();
        bob.b = 2;
        printf("bob.a --> %d, bob.b --> %d",bob.a, bob.b);
    }
    

    Para começar, a primeira cópia de sinto s0causará uma cópia, o que significa que cada campo será acessado, o que significa que você tem um comportamento indefinido aqui. Supondo que isso não cause uma falha no seu compilador específico, o retorno também será um comportamento indefinido.

    Abaixo de tudo isso, presumindo que não haja travamentos porque o compilador o tratou de qualquer maneira, a bob.b = 2atribuição torna tudo OK para a instrução print. Assim, você pode se safar de um comportamento indefinido se o seu compilador for cúmplice do código incorreto. Mas sem essa atribuição extra, você também teria um comportamento indefinido no acesso na printf()chamada, e com o compilador cúmplice ou não, o problema finalmente ficaria evidente.

    É claro que ponteiros para estruturas também são frequentemente usados, e isso fica mais complicado... com os ponteiros, você está apenas copiando um endereço, portanto não terá um comportamento indefinido até acessar os campos. Claro, você também deve considerar cópia profunda versus cópia superficial, e se você mantiver scomo uma variável local para essa função, você terá OUTRO comportamento indefinido porque agora você terá uma desreferência de ponteiro ilegal, pois estava apontando para empilhar isso estará fora do escopo quando você voltar ao main. Mas, se você colocar essa estrutura sno escopo global, de repente você poderá atribuir o campo be ficar completamente bem, sem nunca ter comportamentos indefinidos ao acessar variáveis ​​não inicializadas.

    Claro, então você tem a confusão de variáveis ​​no escopo global....

    • 0
  3. Support Ukraine
    2023-09-07T03:15:29+08:002023-09-07T03:15:29+08:00

    A pergunta afirma que

    int x;
    int y = x;
    

    é um comportamento indefinido.

    Isto é errado. O xtem um "valor indeterminado", mas não é o mesmo que comportamento indefinido.

    O padrão permite representações de armadilhas, mas isso é muito raro em intprocessadores convencionais, então vamos esquecer as armadilhas.

    Nesse caso yobterá "algum valor" e o manterá enquanto o acesso xpoderá produzir (de acordo com o padrão) resultados diferentes sempre que for acessado.

    Exatamente o mesmo se aplica ao struct. Nenhum comportamento indefinido. Apenas valores indeterminados. Retornar a estrutura ou atribuir a outra estrutura não fará nenhuma diferença. O objeto está lá... você simplesmente não sabe o que o acesso s.blhe dará.

    • -1
  4. supercat
    2023-09-07T02:42:15+08:002023-09-07T02:42:15+08:00

    Não creio que o Comitê alguma vez tenha considerado essa questão, ou que os membros tivessem um entendimento consensual sobre como respondê-la. Um ponto fraco do Padrão é que seu modelo de abstração não consegue lidar de forma útil com situações em que as otimizações podem afetar o comportamento do programa de maneiras que podem ser irrelevantes para os requisitos da aplicação. Considere, por exemplo:

    struct blob { int count; char arr[32]; } x,y;
    void test1(void)
    {
      struct blob temp;
      temp.count = 2;
      temp.arr[0] = 1;
      temp.arr[1] = 2;
      x = temp;
      y = temp;
    }
    void test(void)
    {
      test1();
      fwrite(&x, 1, sizeof (struct blob), someFile);
      fwrite(&y, 1, sizeof (struct blob), someFile);
    }
    

    Se nada no universo se importasse com o conteúdo de dat[2..31] nas estruturas que são gravadas no arquivo, a maneira mais eficiente de processar o código seria simplesmente escrever as partes iniciais de teste x, ydeixando o resto segurando tudo o que seguravam antes da ligação. Não creio que houvesse consenso entre os membros do Comitê de que tal otimização fosse proibida, mas não há como permitir sem caracterizar a test()função acima. Por outro lado, se a única maneira de um programador garantir algo sobre o comportamento do programa seria garantir que todas as partes do tempforam escritas antes de copiá-lo para xe y, então a "otimização" que servia apenas para justificar o tratamentotest1()já que invocar UB seria discutível e inútil, significando assim que não haveria razão para não tratar partes não escritas de temp.arrcomo contendo valores não especificados (o que resultaria em x.arrconteúdo y.arridêntico).

    • -2

relate perguntas

  • Multiplicação mais rápida que *

  • Usando uma macro para comprimento de string no especificador de formato scanf () em C

  • Como você pode definir o tipo de dados de #define para long double?

  • Ponteiros const incompatíveis

  • Mudança de cor não gradual no OpenGL

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    destaque o código em HTML usando <font color="#xxx">

    • 2 respostas
  • Marko Smith

    Por que a resolução de sobrecarga prefere std::nullptr_t a uma classe ao passar {}?

    • 1 respostas
  • Marko Smith

    Você pode usar uma lista de inicialização com chaves como argumento de modelo (padrão)?

    • 2 respostas
  • Marko Smith

    Por que as compreensões de lista criam uma função internamente?

    • 1 respostas
  • Marko Smith

    Estou tentando fazer o jogo pacman usando apenas o módulo Turtle Random e Math

    • 1 respostas
  • Marko Smith

    java.lang.NoSuchMethodError: 'void org.openqa.selenium.remote.http.ClientConfig.<init>(java.net.URI, java.time.Duration, java.time.Duratio

    • 3 respostas
  • Marko Smith

    Por que 'char -> int' é promoção, mas 'char -> short' é conversão (mas não promoção)?

    • 4 respostas
  • Marko Smith

    Por que o construtor de uma variável global não é chamado em uma biblioteca?

    • 1 respostas
  • Marko Smith

    Comportamento inconsistente de std::common_reference_with em tuplas. Qual é correto?

    • 1 respostas
  • Marko Smith

    Somente operações bit a bit para std::byte em C++ 17?

    • 1 respostas
  • Martin Hope
    fbrereto Por que a resolução de sobrecarga prefere std::nullptr_t a uma classe ao passar {}? 2023-12-21 00:31:04 +0800 CST
  • Martin Hope
    比尔盖子 Você pode usar uma lista de inicialização com chaves como argumento de modelo (padrão)? 2023-12-17 10:02:06 +0800 CST
  • Martin Hope
    Amir reza Riahi Por que as compreensões de lista criam uma função internamente? 2023-11-16 20:53:19 +0800 CST
  • Martin Hope
    Michael A formato fmt %H:%M:%S sem decimais 2023-11-11 01:13:05 +0800 CST
  • Martin Hope
    God I Hate Python std::views::filter do C++20 não filtrando a visualização corretamente 2023-08-27 18:40:35 +0800 CST
  • Martin Hope
    LiDa Cute Por que 'char -> int' é promoção, mas 'char -> short' é conversão (mas não promoção)? 2023-08-24 20:46:59 +0800 CST
  • Martin Hope
    jabaa Por que o construtor de uma variável global não é chamado em uma biblioteca? 2023-08-18 07:15:20 +0800 CST
  • Martin Hope
    Panagiotis Syskakis Comportamento inconsistente de std::common_reference_with em tuplas. Qual é correto? 2023-08-17 21:24:06 +0800 CST
  • Martin Hope
    Alex Guteniev Por que os compiladores perdem a vetorização aqui? 2023-08-17 18:58:07 +0800 CST
  • Martin Hope
    wimalopaan Somente operações bit a bit para std::byte em C++ 17? 2023-08-17 17:13:58 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve