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 / 问题

All perguntas(coding)

Martin Hope
Alphin Thomas
Asked: 2025-03-06 19:08:51 +0800 CST

Um compilador C pode rejeitar legalmente um programa se a profundidade da pilha de chamadas exceder um limite fixo em tempo de compilação?

  • 11

Li que C não exige um tamanho mínimo de pilha, deixando-o definido pela implementação. Mas um compilador C em conformidade poderia se recusar a compilar um programa se ele detectar — digamos, por meio de análise estática — que a profundidade da pilha de chamadas (por exemplo, de uma chamada de função aninhada) excede um limite fixo que ele suporta? Ou isso é sempre um problema de tempo de execução? Estou curioso para saber se o padrão C (como C11 ou C23) permite rejeitar sintaxe válida em tempo de compilação com base apenas na profundidade da pilha, assumindo que não há recursão ou comportamento indefinido

c
  • 1 respostas
  • 99 Views
Martin Hope
Kaiyakha
Asked: 2025-01-22 01:02:59 +0800 CST

Obter ponteiro para membro de classe derivado tornado público com declaração using

  • 11

Considere uma classe base com alguns campos públicos e uma classe derivada que herda a base privadamente e torna um dos campos herdados público por meio da usingdeclaração. Preciso acessar esse campo público da classe derivada com um ponteiro de membro. Aqui está um código:

#include <iostream>

class Base
{
public:
    int derived_public_field = 1;
    int derived_private_field = 1;
};


class Derived : private Base
{
public:
    using Base::derived_public_field;
};


int main() {
    Derived d;
    int Derived::* member_ptr = &Derived::derived_public_field;
    d.*member_ptr = 2;
    std::cout << d.derived_public_field << '\n';
}

Isso não funciona, pois a &Derived::derived_public_fieldexpressão faz com que o compilador (tentei Clang e GCC) pense que estou tentando acessar uma base inacessível. GCC diz:

error: 'Base' is an inaccessible base of 'Derived'

Eu também tentei isso:

int Base::* member_ptr = &Base::derived_public_field;

o que fez com que o mesmo erro aparecesse mais tarde, quando tentei escrever um valor por meio do ponteiro.

Existe uma maneira de fazer o compilador ver que derived_public_fieldé realmente acessível?

c++
  • 2 respostas
  • 124 Views
Martin Hope
Jon
Asked: 2024-12-29 05:11:19 +0800 CST

Como faço para forçar a desativação de exceções do C++?

  • 11

Estou usando C++ para um projeto de firmware de baixo nível para um microcontrolador. Tudo estava bem por um tempo, com o tamanho do código mantido muito pequeno, até que introduzi esta linha de código:

    uint8_t index = __builtin_ctz(exti_set_mask);
    auto &gpio_irq_info = irq_callback_table[index];

O problema aqui é que irq_callback_tableé um std::array<>de tamanho 16. exti_set_maskÉ um uint16_tque provavelmente está sendo promovido para uma uint32_t(arquitetura de CPU de 32 bits), então o compilador não pode ter certeza de que o resultado de __builtin_ctz()retorna algo menor que 16. Com o potencial de um acesso fora dos limites, o tamanho do código do programa explode por causa de todo o código adicionado para dar suporte ao lançamento de uma exceção.

Mascarar o resultado antes de usá-lo como índice elimina todo esse código de exceção:

uint8_t index = __builtin_ctz(exti_set_mask) & 0xf;
auto &gpio_irq_info = irq_callback_table[index];

O que reduz o tamanho do código do programa para cerca de 4 kB contra 90 kB!

Tenho essas bandeiras definidas via meson:

# Specify global compiler flags.
add_project_arguments(
    # Free standing environment (no OS, or stdlib)
    '-ffreestanding', '-nostdlib', '-specs=nosys.specs',
    # Enable linker garbage collection
    '-ffunction-sections', '-fdata-sections',
    # No dynamic memory allocation
    '-fno-builtin-malloc', '-fno-builtin-calloc',
    '-fno-builtin-realloc', '-fno-builtin-free',
    # Debug optimization
    '-Og',
    language: ['cpp', 'c']
)
add_project_arguments(
    '-std=c++20',
    '-fno-exceptions',
    '-fno-rtti',
    language: ['cpp']
)

Mas o -fno-exceptionssinalizador não parece ser suficiente para evitar a emissão de código de exceção. Idealmente, eu gostaria que qualquer emissão potencial de exceções (ou malloc, etc.) aparecesse como um aviso ou erro. Alguma ideia de como fazer isso?


EDIT: Para aqueles que desejam comparar a saída do arquivo .elf objdump, aqui está o .elf totalmente vinculado com o índice mascarado: https://pastebin.com/hSJgF3PW

E o .elf com o índice não mascarado:

  • https://pastebin.com/p9yDxdjx pt1
  • https://pastebin.com/NU5nV0tr pt2
  • https://pastebin.com/9CX1EtH0 pt3
  • https://pastebin.com/evvnmCCa pt4

A função onde os dois se desviam:

Índice não mascarado:

08000d1c <(anonymous namespace)::CommonISRHandler(unsigned short)>:
void CommonISRHandler([[maybe_unused]] uint16_t exti_set_mask) {
 8000d1c:   b570        push    {r4, r5, r6, lr}
 8000d1e:   0005        movs    r5, r0
  while (exti_set_mask) {
 8000d20:   e011        b.n 8000d46 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x2a>
      // Element access.
      [[__nodiscard__]]
      _GLIBCXX17_CONSTEXPR reference
      operator[](size_type __n) noexcept
      {
    __glibcxx_requires_subscript(__n);
 8000d22:   4b18        ldr r3, [pc, #96]   @ (8000d84 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x68>)
 8000d24:   4a18        ldr r2, [pc, #96]   @ (8000d88 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x6c>)
 8000d26:   4819        ldr r0, [pc, #100]  @ (8000d8c <(anonymous namespace)::CommonISRHandler(unsigned short)+0x70>)
 8000d28:   21ca        movs    r1, #202    @ 0xca
 8000d2a:   f000 f97d   bl  8001028 <std::__glibcxx_assert_fail(char const*, int, char const*, char const*)>
    EXTI->RPR1 &= (1 << index);
 8000d2e:   4a18        ldr r2, [pc, #96]   @ (8000d90 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x74>)
 8000d30:   68d1        ldr r1, [r2, #12]
 8000d32:   2301        movs    r3, #1
 8000d34:   40a3        lsls    r3, r4
 8000d36:   4019        ands    r1, r3
 8000d38:   60d1        str r1, [r2, #12]
    EXTI->FPR1 &= (1 << index);
 8000d3a:   6911        ldr r1, [r2, #16]
 8000d3c:   4019        ands    r1, r3
 8000d3e:   6111        str r1, [r2, #16]
    exti_set_mask &= ~(1 << index);
 8000d40:   43db        mvns    r3, r3
 8000d42:   b21b        sxth    r3, r3
 8000d44:   401d        ands    r5, r3
  while (exti_set_mask) {
 8000d46:   2d00        cmp r5, #0
 8000d48:   d01a        beq.n   8000d80 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x64>
    uint8_t index = __builtin_ctz(exti_set_mask);
 8000d4a:   0028        movs    r0, r5
 8000d4c:   f7ff fa40   bl  80001d0 <__ctzsi2>
    auto &gpio_irq_info = irq_callback_table[index];
 8000d50:   24ff        movs    r4, #255    @ 0xff
 8000d52:   4004        ands    r4, r0
 8000d54:   2c0f        cmp r4, #15
 8000d56:   d8e4        bhi.n   8000d22 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x6>
    return stub_ptr != nullptr;
 8000d58:   4b0e        ldr r3, [pc, #56]   @ (8000d94 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x78>)
 8000d5a:   0062        lsls    r2, r4, #1
 8000d5c:   1912        adds    r2, r2, r4
 8000d5e:   0092        lsls    r2, r2, #2
 8000d60:   189b        adds    r3, r3, r2
 8000d62:   689b        ldr r3, [r3, #8]
    if (gpio_irq_info.callback.IsValid()) {
 8000d64:   2b00        cmp r3, #0
 8000d66:   d0e2        beq.n   8000d2e <(anonymous namespace)::CommonISRHandler(unsigned short)+0x12>
      gpio_irq_info.callback(gpio_irq_info.pin);
 8000d68:   4a0a        ldr r2, [pc, #40]   @ (8000d94 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x78>)
 8000d6a:   0060        lsls    r0, r4, #1
 8000d6c:   1901        adds    r1, r0, r4
 8000d6e:   0089        lsls    r1, r1, #2
 8000d70:   5c89        ldrb    r1, [r1, r2]
 8000d72:   1900        adds    r0, r0, r4
 8000d74:   0080        lsls    r0, r0, #2
 8000d76:   1880        adds    r0, r0, r2
 8000d78:   3004        adds    r0, #4
 8000d7a:   f7ff ffbb   bl  8000cf4 <rtlib::Delegate<void (mcu::stm32g070::Gpio::GpioId)>::operator()(mcu::stm32g070::Gpio::GpioId) const>
 8000d7e:   e7d6        b.n 8000d2e <(anonymous namespace)::CommonISRHandler(unsigned short)+0x12>
}
 8000d80:   bd70        pop {r4, r5, r6, pc}
 8000d82:   46c0        nop         @ (mov r8, r8)
 8000d84:   08013ccc    .word   0x08013ccc
 8000d88:   08013ce0    .word   0x08013ce0
 8000d8c:   08013dc4    .word   0x08013dc4
 8000d90:   40021800    .word   0x40021800
 8000d94:   20000734    .word   0x20000734

Índice mascarado:

08000710 <(anonymous namespace)::CommonISRHandler(unsigned short)>:
void CommonISRHandler([[maybe_unused]] uint16_t exti_set_mask) {
 8000710:   b570        push    {r4, r5, r6, lr}
 8000712:   0005        movs    r5, r0
  while (exti_set_mask) {
 8000714:   e00b        b.n 800072e <(anonymous namespace)::CommonISRHandler(unsigned short)+0x1e>
    EXTI->RPR1 &= (1 << index);
 8000716:   4a14        ldr r2, [pc, #80]   @ (8000768 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x58>)
 8000718:   68d1        ldr r1, [r2, #12]
 800071a:   2301        movs    r3, #1
 800071c:   40a3        lsls    r3, r4
 800071e:   4019        ands    r1, r3
 8000720:   60d1        str r1, [r2, #12]
    EXTI->FPR1 &= (1 << index);
 8000722:   6911        ldr r1, [r2, #16]
 8000724:   4019        ands    r1, r3
 8000726:   6111        str r1, [r2, #16]
    exti_set_mask &= ~(1 << index);
 8000728:   43db        mvns    r3, r3
 800072a:   b21b        sxth    r3, r3
 800072c:   401d        ands    r5, r3
  while (exti_set_mask) {
 800072e:   2d00        cmp r5, #0
 8000730:   d018        beq.n   8000764 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x54>
    uint8_t index = __builtin_ctz(exti_set_mask) & 0xf;
 8000732:   0028        movs    r0, r5
 8000734:   f7ff fcc0   bl  80000b8 <__ctzsi2>
 8000738:   240f        movs    r4, #15
 800073a:   4004        ands    r4, r0
    return stub_ptr != nullptr;
 800073c:   4b0b        ldr r3, [pc, #44]   @ (800076c <(anonymous namespace)::CommonISRHandler(unsigned short)+0x5c>)
 800073e:   0062        lsls    r2, r4, #1
 8000740:   1912        adds    r2, r2, r4
 8000742:   0092        lsls    r2, r2, #2
 8000744:   189b        adds    r3, r3, r2
 8000746:   689b        ldr r3, [r3, #8]
    if (gpio_irq_info.callback.IsValid()) {
 8000748:   2b00        cmp r3, #0
 800074a:   d0e4        beq.n   8000716 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x6>
      gpio_irq_info.callback(gpio_irq_info.pin);
 800074c:   4a07        ldr r2, [pc, #28]   @ (800076c <(anonymous namespace)::CommonISRHandler(unsigned short)+0x5c>)
 800074e:   0060        lsls    r0, r4, #1
 8000750:   1901        adds    r1, r0, r4
 8000752:   0089        lsls    r1, r1, #2
 8000754:   5c89        ldrb    r1, [r1, r2]
 8000756:   1900        adds    r0, r0, r4
 8000758:   0080        lsls    r0, r0, #2
 800075a:   1880        adds    r0, r0, r2
 800075c:   3004        adds    r0, #4
 800075e:   f7ff ffc3   bl  80006e8 <rtlib::Delegate<void (mcu::stm32g070::Gpio::GpioId)>::operator()(mcu::stm32g070::Gpio::GpioId) const>
 8000762:   e7d8        b.n 8000716 <(anonymous namespace)::CommonISRHandler(unsigned short)+0x6>
}
 8000764:   bd70        pop {r4, r5, r6, pc}
 8000766:   46c0        nop         @ (mov r8, r8)
 8000768:   40021800    .word   0x40021800
 800076c:   2000005c    .word   0x2000005c

EDIT #2 , Alguns bons comentários até agora, obrigado. Minha razão para acreditar que exceções estão sendo puxadas é por causa da presença de muitas funções no objdump não mascarado que não estão presentes na saída do objdump mascarado ( grep -i exception, grep -i throw):

08000438 <_Unwind_RaiseException>:
 800045e:       f009 f831       bl      80094c4 <__gnu_Unwind_RaiseException>
 8001764:       f007 fb0e       bl      8008d84 <__cxa_current_exception_type>
080089d8 <__cxxabiv1::__is_gxx_exception_class(char*)>:
 80089e0:       d000            beq.n   80089e4 <__cxxabiv1::__is_gxx_exception_class(char*)+0xc>
 80089e8:       d1fb            bne.n   80089e2 <__cxxabiv1::__is_gxx_exception_class(char*)+0xa>
 80089ee:       d1f8            bne.n   80089e2 <__cxxabiv1::__is_gxx_exception_class(char*)+0xa>
 80089f4:       d1f5            bne.n   80089e2 <__cxxabiv1::__is_gxx_exception_class(char*)+0xa>
 80089fa:       d1f2            bne.n   80089e2 <__cxxabiv1::__is_gxx_exception_class(char*)+0xa>
 8008a00:       d1ef            bne.n   80089e2 <__cxxabiv1::__is_gxx_exception_class(char*)+0xa>
 8008a06:       d1ec            bne.n   80089e2 <__cxxabiv1::__is_gxx_exception_class(char*)+0xa>
 8008a12:       e7e6            b.n     80089e2 <__cxxabiv1::__is_gxx_exception_class(char*)+0xa>
 8008a20:       f7ff ffda       bl      80089d8 <__cxxabiv1::__is_gxx_exception_class(char*)>
 8008a44:       f7ff ffc8       bl      80089d8 <__cxxabiv1::__is_gxx_exception_class(char*)>
 8008b02:       f000 fad3       bl      80090ac <__cxa_allocate_exception>
 8008bc0:       f000 fce6       bl      8009590 <_Unwind_DeleteException>
 8008c2c:       f000 fcb0       bl      8009590 <_Unwind_DeleteException>
08008c34 <std::bad_exception::~bad_exception()>:
08008c38 <transaction clone for std::bad_exception::what() const>:
 8008c38:       4800            ldr     r0, [pc, #0]    @ (8008c3c <transaction clone for std::bad_exception::what() const+0x4>)
08008c40 <std::bad_exception::~bad_exception()>:
08008c60 <__gxx_exception_cleanup(_Unwind_Reason_Code, _Unwind_Control_Block*)>:
 8008c64:       d812            bhi.n   8008c8c <__gxx_exception_cleanup(_Unwind_Reason_Code, _Unwind_Control_Block*)+0x2c>
 8008c72:       d000            beq.n   8008c76 <__gxx_exception_cleanup(_Unwind_Reason_Code, _Unwind_Control_Block*)+0x16>
 8008c7e:       d001            beq.n   8008c84 <__gxx_exception_cleanup(_Unwind_Reason_Code, _Unwind_Control_Block*)+0x24>
 8008c86:       f000 fa27       bl      80090d8 <__cxa_free_exception>
 8008c8a:       e7f3            b.n     8008c74 <__gxx_exception_cleanup(_Unwind_Reason_Code, _Unwind_Control_Block*)+0x14>
08008c94 <__cxa_init_primary_exception>:
 8008cd0:       4b02            ldr     r3, [pc, #8]    @ (8008cdc <__cxa_init_primary_exception+0x48>)
 8008cf8:       f7ff ffcc       bl      8008c94 <__cxa_init_primary_exception>
 8008d06:       f7f7 fb97       bl      8000438 <_Unwind_RaiseException>
08008d84 <__cxa_current_exception_type>:
 8008d8e:       d004            beq.n   8008d9a <__cxa_current_exception_type+0x16>
 8008d96:       d001            beq.n   8008d9c <__cxa_current_exception_type+0x18>
 8008da0:       e7fa            b.n     8008d98 <__cxa_current_exception_type+0x14>
080090ac <__cxa_allocate_exception>:
 80090b8:       d007            beq.n   80090ca <__cxa_allocate_exception+0x1e>
 80090d2:       d1f2            bne.n   80090ba <__cxa_allocate_exception+0xe>
080090d8 <__cxa_free_exception>:
 80090d8:       4b07            ldr     r3, [pc, #28]   @ (80090f8 <__cxa_free_exception+0x20>)
 80090e6:       d201            bcs.n   80090ec <__cxa_free_exception+0x14>
 80090ea:       d302            bcc.n   80090f2 <__cxa_free_exception+0x1a>
 80090f6:       e7fb            b.n     80090f0 <__cxa_free_exception+0x18>
080094c4 <__gnu_Unwind_RaiseException>:
 80094e0:       e006            b.n     80094f0 <__gnu_Unwind_RaiseException+0x2c>
 80094ee:       d108            bne.n   8009502 <__gnu_Unwind_RaiseException+0x3e>
 80094fa:       d0f2            beq.n   80094e2 <__gnu_Unwind_RaiseException+0x1e>
 800950a:       d1f7            bne.n   80094fc <__gnu_Unwind_RaiseException+0x38>
 8009584:       f7ff ff9e       bl      80094c4 <__gnu_Unwind_RaiseException>
08009590 <_Unwind_DeleteException>:
 8009598:       d001            beq.n   800959e <_Unwind_DeleteException+0xe>

08000498 <_Unwind_Resume_or_Rethrow>:
 80004be:       f009 f857       bl      8009570 <__gnu_Unwind_Resume_or_Rethrow>
 80017c6:       f007 faa5       bl      8008d14 <__cxa_rethrow>
 8008ad0:       f000 f920       bl      8008d14 <__cxa_rethrow>
 8008b0e:       f000 f8e7       bl      8008ce0 <__cxa_throw>
08008ce0 <__cxa_throw>:
08008d14 <__cxa_rethrow>:
 8008d24:       d00c            beq.n   8008d40 <__cxa_rethrow+0x2c>
 8008d2c:       d00a            beq.n   8008d44 <__cxa_rethrow+0x30>
 8008d36:       f7f7 fbaf       bl      8000498 <_Unwind_Resume_or_Rethrow>
 8008d4a:       d1f0            bne.n   8008d2e <__cxa_rethrow+0x1a>
 8008d52:       d1ec            bne.n   8008d2e <__cxa_rethrow+0x1a>
 8008d5a:       d1e8            bne.n   8008d2e <__cxa_rethrow+0x1a>
 8008d62:       d1e4            bne.n   8008d2e <__cxa_rethrow+0x1a>
 8008d6a:       d1e0            bne.n   8008d2e <__cxa_rethrow+0x1a>
 8008d72:       d1dc            bne.n   8008d2e <__cxa_rethrow+0x1a>
 8008d7a:       d8d8            bhi.n   8008d2e <__cxa_rethrow+0x1a>
 8008d82:       e7d6            b.n     8008d32 <__cxa_rethrow+0x1e>
08009570 <__gnu_Unwind_Resume_or_Rethrow>:
 8009576:       d005            beq.n   8009584 <__gnu_Unwind_Resume_or_Rethrow+0x14>
 8009588:       e7fb            b.n     8009582 <__gnu_Unwind_Resume_or_Rethrow+0x12>
c++
  • 2 respostas
  • 191 Views
Martin Hope
Desmond Gold
Asked: 2024-12-01 12:20:14 +0800 CST

O pacote de vinculação estruturado permite pacote vazio a partir de objeto de tamanho de tupla zero?

  • 11

Associações estruturadas não permitem tipos decomponíveis vazios.

auto [] = std::make_tuple(); // error

Desde que P1061R10 foi aceito para C++26, isso permite que ligações estruturadas introduzam pacotes (desde que o pacote seja declarado dentro do contexto do modelo):

auto [...args] = return_empty_tuple();
auto [one, ...rest] = return_single_tuple();

Este último permite ...restser um pacote vazio se return_single_tuple()tiver um tamanho de ligação estruturado de 1.

Minha pergunta é: ...argsainda é possível declarar um pacote vazio mesmo que return_empty_tuple()tenha um tamanho de ligação estruturada zero (por exemplo, tamanho de tupla zero)?

c++
  • 2 respostas
  • 138 Views
Martin Hope
Ian Boyd
Asked: 2024-11-23 15:32:15 +0800 CST

Uma resourcestring é uma string ou um registro e preciso usar LoadResString para carregá-la?

  • 11

Na unidade Vcl.Buttons do Delphi eles chamam:

Caption := LoadResString(BitBtnCaptions[Value]);

Onde BitnBtnCaptionsestá uma matriz como:

BitnBtnCaptions: array[TBitBtnKind] of Pointer = (
        nil, @SOKButton, @SCancelButton, @SHelpButton, @SYesButton, @SNoButton,
        @SCloseButton, @SAbortButton, @SRetryButton, @SIgnoreButton,
        @SAllButton);

E as BitnBtnCaptionsconstantes são:

resourcestring
  SOKButton = 'OK';
  SCancelButton = 'Cancel';
  SYesButton = '&Yes';
  SNoButton = '&No';
  SHelpButton = '&Help';
  SCloseButton = '&Close';
  SIgnoreButton = '&Ignore';
  SRetryButton = '&Retry';
  SAbortButton = 'Abort';
  SAllButton = '&All';

Então, basicamente, ele está chamando:

resourcestring
  SOKButton = 'OK';

s := LoadResString(@SOKButton);

A declaração de LoadResString é:

function LoadResString(ResStringRec: PResStringRec): string;

Esta função requer um ponteiro para um TResStringRec :

PResStringRec = ^TResStringRec;
TResStringRec = packed record
   // 32bit = 8 bytes
   // 64bit = 16 bytes
   Module: ^HMODULE;
   Identifier: NativeUint;
end;

Mas estamos passando uma resourcestring .

Isso significa que estamos passando uma string para uma função que só aceita um PResStringRec em caso de erro?

Por que você pergunta?

Pergunto porque estou chamando:

Result := LoadResString(@SMsgDlgOK);

e com avaliação de ponteiro digitado ( ie {$T+} ou {$TYPEDADDRESS ON}) ele emite um aviso de tipo incompatível:

E2010 Tipos incompatíveis: 'PResStringRec' e 'Pointer'

E é claro que eu posso simplesmente forçar com um elenco forte:

Result := LoadResString(PResStringRec(@SMsgDlgOK));

Elenco difícil?

Mas isso parece um pouco duro para algo que supostamente é a maneira correta de fazer algo. Cheira um pouco estranho.

E o pior é que se estou fazendo um gesso forte , é melhor saber o que estou fazendo.

E do jeito que eu vejo, a única maneira de isso funcionar é se:

  • a constante mágicaSMsgDlgOk
  • na verdade é um TResStringRec.

Não queremos forçar uma peça triangular no furo quadrado , usando um molde rígido às cegas.

O que me leva à minha pergunta: uma resourcestring

resourcestring
  SMsgDlgOK = 'OK';

uma string? Ou é um registro?

Mas eu realmente tenho que fazer isso?

Eu preciso realmente fazer o que ele Vcl.Buttonsfaz? Vcl.ButtonsPrecisa fazer o que ele está fazendo?

Não podemos simplesmente substituir:

s := LoadResString(@SOKButton);

com

s := SOKButton

Não era esse o ponto principal da palavra-chave resourcestring ? Ela coloca as strings na tabela strings (onde os localizadores podem localizá-las) e faz toda a mágica em tempo de execução (ou seja, LoadResString ) para expor as resourcestrings como strings ?

E se isso não for verdade: por que não?

  • O que é resourcestring?
  • e como ele difere de LoadResString(resourceString)?

O que ganho ligando para:

LoadResString(@SOKButton)

sobre apenas usar SOKButton ?

E se eu tiver que usar LoadResString , é realmente , realmente , verdadeiramente , juro, 100% seguro forçar o typecast?

  • Ideal :s := SOKButton
  • Atual : s := LoadResString(@SOKButton)// falha na verificação de ponteiro digitado
  • Correto (?) :s := LoadResString(PResStringRec(@SOKButton))

Bate-papo bônus

Se um resourcestring realmente for um TResStringRect, então eu deveria ser capaz de vê-lo. Então eu inspeciono o que eles são:

╔════════════════════════════╤══════════╗
║ Watch Name                 │ Value    ║
╠════════════════════════════╪══════════╣
║ PResStringRec(@SMsgDlgOK)  │ $AD3C54  ║
║ ├──Module                  │ $400000  ║
║ ╰──Identifier              │ 0        ║
╟┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┼┈┈┈┈┈┈┈┈┈┈╢
║ PResStringRec(@SMsgDlgYes) │ $AD3C54  ║
║ ├──Module                  │ $400000  ║
║ ╰──Identifier              │ 0        ║
╟┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┼┈┈┈┈┈┈┈┈┈┈╢
║ PResStringRec(@SMsgDlgNo)  │ $AD3C54  ║
║ ├──Module                  │ $400000  ║
║ ╰──Identifier              │ 0        ║
╚════════════════════════════╧══════════╝

Cada sequência de recursos:

  • mora no mesmo endereço
  • tem o mesmo módulo
  • tem o mesmo identificador

Então algo não está certo; não parece um disco para mim.

Então por que o código funciona Vcl.Buttons?

delphi
  • 1 respostas
  • 102 Views
Martin Hope
PiotrNycz
Asked: 2024-11-13 21:50:04 +0800 CST

std::ranges::sort não funciona com operador não padrão<=>?

  • 11

Tenho um caso em que o tipo struct não precisa ser padrão operator<=>- só que nem todos os campos são importantes ao definir a ordem dos objetos.

struct A
{
    int a;
    int b; // not important when ordering
    int c;

    constexpr std::strong_ordering operator<=>(const A& rhs) const
    {
        if (const auto res = a<=>rhs.a; res != 0) return res;
        return c<=>rhs.c;
    }
};

Para minha surpresa, não posso usar container com esse tipo como argumento para std::ranges::sort:

std::array<A, 100> aa{};
std::ranges::sort(aa);

Eu verifiquei no mais novo gcc (14) e clang (19) e ele basicamente afirma que o intervalo não é classificável porque std::invocable_v<std::ranges::less&, A&, A&>não é verdade. Veja o link godbold

Mais observações:

  1. Funciona com std::sort( std::sort(aa.begin(), aa.end());)
  2. Funciona ao adicionar não padrãooperator==
  3. E funciona com o padrão ( =default)operator<=>

Isso é um bug do compilador, um bug padrão do C++ ou alguma regra estranha do C++ está em jogo aqui e deveria ser assim? Se a última opção estiver correta - você pode fornecer uma justificativa para tal comportamento?


Atualizar:

Pelos comentários parece que std::ranges::less{}(A{}, A{})requer não apenas operator<(derivado de operator<=>), mas também operator==que não pode ser derivado de não padrão, operator<=>então o erro.

Mas uma questão permanece: por que std::ranges::lessas necessidades operator==?

E melhor exemplo dos comentários: link

c++
  • 2 respostas
  • 117 Views
Martin Hope
eyelash
Asked: 2024-11-05 02:19:15 +0800 CST

Compreendendo a otimização SIMD do Clang para multiplicar um float por um contador de loop int

  • 11

Dada a seguinte função

void foo(float* result, int size, float y, float delta) {
    for (int t = 0; t < size; ++t) {
        result[t] = y + delta * t;
    }
}

O Clang -O2 gera o seguinte assembly x86-64 :

.LCPI0_0:
        .long   0
        .long   1
        .long   2
        .long   3
.LCPI0_1:
        .long   4
        .long   4
        .long   4
        .long   4
.LCPI0_2:
        .long   65535
        .long   65535
        .long   65535
        .long   65535
.LCPI0_3:
        .long   1258291200
        .long   1258291200
        .long   1258291200
        .long   1258291200
.LCPI0_4:
        .long   1392508928
        .long   1392508928
        .long   1392508928
        .long   1392508928
.LCPI0_5:
        .long   0x53000080
        .long   0x53000080
        .long   0x53000080
        .long   0x53000080
.LCPI0_6:
        .long   8
        .long   8
        .long   8
        .long   8
foo(float*, int, float, float):
        test    esi, esi
        jle     .LBB0_7
        mov     eax, esi
        cmp     esi, 7
        ja      .LBB0_3
        xor     ecx, ecx
        jmp     .LBB0_6
.LBB0_3:
        mov     ecx, eax
        and     ecx, 2147483640
        movaps  xmm2, xmm1
        shufps  xmm2, xmm1, 0
        movaps  xmm3, xmm0
        shufps  xmm3, xmm0, 0
        mov     edx, eax
        shr     edx, 3
        and     edx, 268435455
        shl     rdx, 5
        movdqa  xmm4, xmmword ptr [rip + .LCPI0_0]
        xor     esi, esi
        movdqa  xmm5, xmmword ptr [rip + .LCPI0_1]
        movdqa  xmm6, xmmword ptr [rip + .LCPI0_2]
        movdqa  xmm7, xmmword ptr [rip + .LCPI0_3]
        movdqa  xmm8, xmmword ptr [rip + .LCPI0_4]
        movaps  xmm9, xmmword ptr [rip + .LCPI0_5]
        movdqa  xmm10, xmmword ptr [rip + .LCPI0_6]
.LBB0_4:
        movdqa  xmm11, xmm4
        paddd   xmm11, xmm5
        movdqa  xmm12, xmm4
        pand    xmm12, xmm6
        por     xmm12, xmm7
        movdqa  xmm13, xmm4
        psrld   xmm13, 16
        por     xmm13, xmm8
        subps   xmm13, xmm9
        addps   xmm13, xmm12
        movdqa  xmm12, xmm11
        pand    xmm12, xmm6
        por     xmm12, xmm7
        psrld   xmm11, 16
        por     xmm11, xmm8
        subps   xmm11, xmm9
        addps   xmm11, xmm12
        mulps   xmm13, xmm2
        addps   xmm13, xmm3
        mulps   xmm11, xmm2
        addps   xmm11, xmm3
        movups  xmmword ptr [rdi + rsi], xmm13
        movups  xmmword ptr [rdi + rsi + 16], xmm11
        paddd   xmm4, xmm10
        add     rsi, 32
        cmp     rdx, rsi
        jne     .LBB0_4
        cmp     ecx, eax
        je      .LBB0_7
.LBB0_6:
        xorps   xmm2, xmm2
        cvtsi2ss        xmm2, ecx
        mulss   xmm2, xmm1
        addss   xmm2, xmm0
        movss   dword ptr [rdi + 4*rcx], xmm2
        inc     rcx
        cmp     rax, rcx
        jne     .LBB0_6
.LBB0_7:
        ret

Estou tentando entender o que está acontecendo aqui. Parece que .LBB0_4é um loop que cobre 8 iterações do loop original para cada iteração (há 2 mulpsinstruções e cada instrução cobre 4 floats e rsié incrementada em 32). O código no final provavelmente está lá para cobrir o caso em que sizenão é divisível por 8. O que estou tendo problemas é o resto do código. O que todas essas outras instruções dentro do .LBB0_4loop e as constantes no início estão fazendo? Existe uma ferramenta ou um argumento do compilador que pode me ajudar a entender o resultado da vetorização SIMD? Talvez algo que transforme isso de volta em C++ com intrínsecos SIMD?

Também se eu mudar o código para isso

void foo(float* result, int size, float y, float delta) {
    for (int t = 0; t < size; ++t) {
        result[t] = y;
        y += delta;
    }
}

O Clang gera uma montagem muito menor e faz um loop em 16 valores de uma só vez .

Edição: Acabei de perceber que esta versão não é vetorizada e, portanto, é menor e provavelmente mais lenta.

Qual é a maneira mais rápida de escrever este código?

c++
  • 1 respostas
  • 126 Views
Martin Hope
jrr
Asked: 2024-10-31 02:30:33 +0800 CST

Fazer com que a atualização avalie uma expressão para cada linha?

  • 11

Problema de alto nível: Quero atualizar uma tabela existente para preencher uma coluna existente com 32 bytes gerados aleatoriamente, codificados em base64. Os dados aleatórios devem ser diferentes para cada linha.

Ignorando por um momento o requisito de codificação base64, a solução é simples, conforme ilustrado neste código de exemplo:

DECLARE @table TABLE (
    id int,
    bin varbinary(max) null
)

-- put a few rows in the table
insert into @table (id) values (1)
insert into @table (id) values (2)
insert into @table (id) values (3)

-- perform the update
update @table
set bin =  CRYPT_GEN_RANDOM(32)

-- check result
select *
from @table

Isso funciona como esperado. CRYPT_GEN_RANDOM(32)gera um valor diferente para cada linha atualizada. Agora tente adicionar o requisito de codificação base64:

DECLARE @table TABLE (
    id int,
    txt nvarchar(max) null
)

-- put a few rows in the table
insert into @table (id) values (1)
insert into @table (id) values (2)
insert into @table (id) values (3)

-- perform the update
update @table
set txt =  (SELECT CRYPT_GEN_RANDOM(32) FOR XML PATH(''), BINARY BASE64)

-- check result
select *
from @table

Isso não funciona: ele coloca o mesmo valor em cada linha. Eu tentei empacotar a codificação base64 em um UDF, para ver se isso ajudaria:

CREATE FUNCTION ConvertBytesToBase64
(
    @bytes varbinary(max)
)
RETURNS nvarchar(max)
AS
BEGIN
    DECLARE @result nvarchar(max)
    SET @result = (SELECT @bytes FOR XML PATH(''), BINARY BASE64)
    RETURN @result
END
GO

E então a declaração de atualização se torna:

update @table
set txt = ConvertBytesToBase64(CRYPT_GEN_RANDOM(32))

Mas isso ainda produz o mesmo valor em todas as linhas.

O que eu fundamentalmente não entendo é, dado que o SQL Server avalia CRYPT_GEN_RANDOM(32)para cada linha (o que parece sensato), por que ele não avalia ConvertBytesToBase64(CRYPT_GEN_RANDOM(32))para cada linha? Como posso fazer com que ele avalie para cada linha? (e talvez relacionado, há uma maneira melhor de fazer codificação base64 no SQL Server 2019+?)

sql
  • 1 respostas
  • 66 Views
Martin Hope
user20726076
Asked: 2024-10-29 21:02:25 +0800 CST

Ligações bidirecionais javafx fora de sincronia

  • 11

Eu estava escrevendo uma classe em javafx onde eu tinha duas propriedades que eram vinculadas bidirecionalmente e estava testando alguns casos extremos. Descobri que se você alterasse o valor de uma das propriedades de dentro de um ouvinte de invalidação, isso fazia com que as propriedades ficassem fora de sincronia. Aqui está um pequeno exemplo:

static class A {
    IntegerProperty x = new SimpleIntegerProperty(this, "x", 0);
    IntegerProperty y = new SimpleIntegerProperty(this, "y", 0);
    A() {
        x.bindBidirectional(y);
    }
}

static void testA() {
    A a = new A();
    a.x.addListener( o -> { //InvalidationListener
        if (a.x.get() < 0) a.x.set(0);
    });
    // after y is set to a negative value, x and y hold different values
    // until either y is set to a value that's >= 0 or x is set to any value
    a.y.set(-2);
    System.out.println(a.x.get());
    System.out.println(a.y.get());
}

Saída:

0
-2

Eu estava assumindo que ao usar uma ligação bidirecional, alterar uma propriedade sempre faria com que a outra fosse atualizada. Parece raro (e possivelmente imprudente) que alguém escrevesse um ouvinte de invalidação como esse, mas estou pensando defensivamente aqui. Se pelo menos uma dessas propriedades fosse exposta, não quero que seja possível quebrar nenhuma invariante da minha classe. Eu estava pensando que há três explicações possíveis aqui:

  1. O contrato em ligações bidirecionais não é que elas sempre estejam em sincronia (ou elas mantêm o mesmo valor ou são marcadas como inválidas), é apenas em uma base de melhor esforço. Assim, invariantes de classe não devem ser baseadas nesse fato.

  2. Alterar o valor dentro de um ouvinte de invalidação quebra a pré-condição de vínculos bidirecionais e deve ser evitado. Caso contrário, eles estão sempre em sincronia. Assim, você pode basear uma invariante de classe nesse fato, já que é razoável exigir que os clientes não escrevam ouvintes de invalidação assim.

  3. É um bug e eles realmente devem ser sincronizados, não importa o que aconteça. Acho que se isso fosse verdade, você poderia facilmente produzir um loop infinito de notificações de alteração (como adicionar um ouvinte de invalidação a y que sempre define o valor como < 0). Então, caberia ao cliente evitar tais casos.

Alguma dessas explicações está próxima da verdade ou estou esquecendo de algo mais aqui? Além disso, eu gostaria de saber se existe algum outro tipo de operação bind que leve esses tipos de situações em consideração.

java
  • 2 respostas
  • 84 Views
Martin Hope
wohlstad
Asked: 2024-10-02 22:03:43 +0800 CST

Uso de std::is_constant_evaluated() desde C++23

  • 11

Entendo que std::is_constant_evaluated()foi útil determinar a avaliação do tempo de compilação em C++20.

Mas desde C++23 temos if consteval.

Entretanto, não há menção de descontinuação para std::is_constant_evaluated().

Existe algum uso prático para isso a partir do C++23?

c++
  • 1 respostas
  • 87 Views
Prev
Próximo

Sidebar

Stats

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

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +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