MIN e MAX em C


301

Onde estão MINe MAXdefinidos em C, se houver?

Qual é a melhor maneira de implementá-las da maneira mais genérica e segura possível? (Preferências de extensões / built-in do compilador para compiladores convencionais).

Respostas:


392

Onde estão MINe MAXdefinidos em C, se houver?

Eles não são.

Qual é a melhor maneira de implementá-las, da maneira mais genérica e segura possível (extensões / compiladores do compilador para compiladores principais preferidos).

Como funções. Eu não usaria macros como #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)), especialmente se você planeja implantar seu código. Escreva você mesmo, use algo como padrão fmaxou fmincorrija a macro usando o typeof do GCC (você também recebe bônus de segurança de tipo) em uma expressão de instrução do GCC :

 #define max(a,b) \
   ({ __typeof__ (a) _a = (a); \
       __typeof__ (b) _b = (b); \
     _a > _b ? _a : _b; })

Todo mundo diz "ah, eu sei sobre avaliação dupla, não há problema" e, alguns meses depois, você estará depurando os problemas mais bobos por horas a fio.

Observe o uso de em __typeof__vez de typeof:

Se você estiver escrevendo um arquivo de cabeçalho que deve funcionar quando incluído nos programas ISO C, escreva em __typeof__vez de typeof.


68
Você sabe, seria bastante útil se o gcc tivesse um aviso ao longo das linhas de: warning: expression with side-effects multiply evaluated by macrono ponto de uso ...
caf 9/08/10

23
@caf: isso não exigiria que o pré-processador tivesse um conhecimento mais complicado da sintaxe C?
dreamlax

3
Depois de muita tentativa de descobrir, acho que não há como fazer isso no VC ++, mas o melhor é tentar mexer com a nova decltypepalavra-chave do MSVC ++ 2010 - mas, mesmo assim, o Visual Studio não pode fazer declarações compostas em macros (e decltypeé C ++ de qualquer maneira), ou seja, ({ ... })sintaxe do GCC, então eu tenho certeza que não é possível. Eu não olhei para quaisquer outros compiladores quanto a esta questão, desculpe Luther: S
David Titarenco

7
@dreamlax Uma vez vi um caso em que alguém havia feito MAX(someUpperBound, someRandomFunction())para limitar um valor aleatório a algum limite superior. Foi uma péssima ideia, mas também nem funcionou, porque o que MAXele estava usando tinha o problema de dupla avaliação, então ele acabou com um número aleatório diferente daquele que foi avaliado inicialmente.
Zev Eisenberg 12/08

8
@Soumen Por exemplo, se você chamar MIN(x++, y++)o pré-processador, irá gerar o seguinte código (((x++) < (y++)) ? (x++) : (y++)). Então, xe yserá incrementado duas vezes.
Antonio

91

Também é fornecido nas versões GNU libc (Linux) e FreeBSD do sys / param.h, e possui a definição fornecida pelo dreamlax.


No Debian:

$ uname -sr
Linux 2.6.11

$ cat /etc/debian_version
5.0.2

$ egrep 'MIN\(|MAX\(' /usr/include/sys/param.h
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

$ head -n 2 /usr/include/sys/param.h | grep GNU
This file is part of the GNU C Library.

No FreeBSD:

$ uname -sr
FreeBSD 5.5-STABLE

$ egrep 'MIN\(|MAX\(' /usr/include/sys/param.h
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

Os repositórios de origem estão aqui:


Adicionei as definições dos sistemas aos quais tenho acesso na minha resposta acima (o campo de comentário não aceita formatação até onde sei). Tentará encontrar os links para os repositórios de código-fonte do FreeBSD / Linux / glibc.
Mikel

+1. Muito agradável. Funciona para openSUSE/Linux 3.1.0-1.2-desktop/ gcc version 4.6.2 (SUSE Linux) também. :) Ruim, não é portátil.
31412 Jack

Também funciona no Cygwin.
CMCDragonkai

1
Espere um momento. Isso não impede a dupla avaliação, não é? : 3
user1857492

76

Existe um std::mine std::maxno C ++, mas no AFAIK, não há equivalente na biblioteca padrão do C. Você mesmo pode defini-los com macros como

#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))

Mas isso causa problemas se você escrever algo parecido MAX(++a, ++b).


10
por que colocar muitos suportes ??? Eu encontrei um questionário onde eles disseram que #define MIN(A, B) ((A < B) ? A : B)não é uma maneira flexível, por que ???

79
@Makouda: Parênteses extras nas macros ajudam a evitar problemas de precedência do operador. Por exemplo, considere #define MULT(x, y) x * y. Em seguida, MULT(a + b, a + b)expande para a + b * a + b, que analisa como a + (b * a) + bdevido à precedência. Não é isso que o programador provavelmente pretendeu.
dan04

que não é necessário quando?: tem a menor precedência de qualquer maneira #
Winger Sendon

1
@ WingerSendon: Não; o operador de vírgula faz.
dan04

24

Evite extensões de compilador não padrão e implemente-a como uma macro completamente segura para o tipo no padrão C (ISO 9899: 2011).

Solução

#define GENERIC_MAX(x, y) ((x) > (y) ? (x) : (y))

#define ENSURE_int(i)   _Generic((i), int:   (i))
#define ENSURE_float(f) _Generic((f), float: (f))


#define MAX(type, x, y) \
  (type)GENERIC_MAX(ENSURE_##type(x), ENSURE_##type(y))

Uso

MAX(int, 2, 3)

Explicação

A macro MAX cria outra macro com base no typeparâmetro. Essa macro de controle, se implementada para o tipo especificado, é usada para verificar se os dois parâmetros são do tipo correto. Se o typenão for suportado, haverá um erro do compilador.

Se x ou y não for do tipo correto, haverá um erro do compilador nas ENSURE_macros. Mais macros podem ser adicionadas se mais tipos forem suportados. Eu assumi que apenas tipos aritméticos (números inteiros, flutuadores, ponteiros etc.) serão usados ​​e não estruturas ou matrizes etc.

Se todos os tipos estiverem corretos, a macro GENERIC_MAX será chamada. Parênteses extras são necessários em torno de cada parâmetro de macro, como a precaução padrão usual ao gravar macros C.

Depois, há os problemas usuais com promoções implícitas de tipos em C. O ?:operador equilibra o 2º e o 3º operando entre si. Por exemplo, o resultado de GENERIC_MAX(my_char1, my_char2)seria um int. Para impedir que a macro faça essas promoções de tipo potencialmente perigosas, foi usada uma conversão de tipo final para o tipo pretendido.

Fundamentação

Queremos que ambos os parâmetros para a macro sejam do mesmo tipo. Se um deles for de um tipo diferente, a macro não será mais um tipo seguro, porque um operador como esse ?:produzirá promoções implícitas de tipo. E, como isso acontece, também sempre precisamos converter o resultado final no tipo pretendido, conforme explicado acima.

Uma macro com apenas um parâmetro poderia ter sido escrita de uma maneira muito mais simples. Mas com 2 ou mais parâmetros, é necessário incluir um parâmetro de tipo extra. Porque algo assim é infelizmente impossível:

// this won't work
#define MAX(x, y)                                  \
  _Generic((x),                                    \
           int: GENERIC_MAX(x, ENSURE_int(y))      \
           float: GENERIC_MAX(x, ENSURE_float(y))  \
          )

O problema é que, se a macro acima for chamada como MAX(1, 2)duas int, ela ainda tentará expandir macro todos os cenários possíveis da _Genericlista de associações. Portanto, a ENSURE_floatmacro também será expandida, mesmo que não seja relevante int. E como essa macro intencionalmente contém apenas o floattipo, o código não será compilado.

Para resolver isso, criei o nome da macro durante a fase de pré-processador, com o operador ##, para que nenhuma macro seja expandida acidentalmente.

Exemplos

#include <stdio.h>

#define GENERIC_MAX(x, y) ((x) > (y) ? (x) : (y))

#define ENSURE_int(i)   _Generic((i), int:   (i))
#define ENSURE_float(f) _Generic((f), float: (f))


#define MAX(type, x, y) \
  (type)GENERIC_MAX(ENSURE_##type(x), ENSURE_##type(y))

int main (void)
{
  int    ia = 1,    ib = 2;
  float  fa = 3.0f, fb = 4.0f;
  double da = 5.0,  db = 6.0;

  printf("%d\n", MAX(int,   ia, ib)); // ok
  printf("%f\n", MAX(float, fa, fb)); // ok

//printf("%d\n", MAX(int,   ia, fa));  compiler error, one of the types is wrong
//printf("%f\n", MAX(float, fa, ib));  compiler error, one of the types is wrong
//printf("%f\n", MAX(double, fa, fb)); compiler error, the specified type is wrong
//printf("%f\n", MAX(float, da, db));  compiler error, one of the types is wrong

//printf("%d\n", MAX(unsigned int, ia, ib)); // wont get away with this either
//printf("%d\n", MAX(int32_t, ia, ib)); // wont get away with this either
  return 0;
}

A GENERIC_MAXpropósito, essa macro é uma péssima idéia; você só precisa tentar GENERIC_MAX(var++, 7)descobrir o motivo :-) Hoje em dia (especialmente com compiladores altamente otimizados / embutidos), as macros devem ser praticamente relegadas apenas aos formulários simples. Os do tipo função são melhores como funções e os do grupo de valor melhores como enumerações.
paxdiablo

21

Não acho que sejam macros padronizadas. Já existem funções padronizadas para ponto flutuante fmaxe fmin(e fmaxfpara flutuadores e fmaxlpara dobras longas).

Você pode implementá-las como macros, desde que esteja ciente dos problemas de efeitos colaterais / avaliação dupla.

#define MAX(a,b) ((a) > (b) ? a : b)
#define MIN(a,b) ((a) < (b) ? a : b)

Na maioria dos casos, você pode deixar para o compilador determinar o que está tentando fazer e otimizá-lo da melhor forma possível. Embora isso cause problemas quando usado como MAX(i++, j++), duvido que exista muita necessidade de verificar o máximo de valores incrementados de uma só vez. Incremente primeiro e depois verifique.


Esta deve ser a resposta preferido como há claramente mínimo e máximo de funções na biblioteca de matemática: cplusplus.com/reference/cmath/fmax
imranal

@ imranal Do que você está falando exatamente? O código de implementação dessas bibliotecas? Mas esse código não é exposto , ou seja, eles não o estão colocando na interface da biblioteca, sendo potencialmente inseguros.
Antonio

@ Antonio Eu acho que você está usando definições incorretas de "exposto" e "interface". A interface da biblioteca ac são variáveis ​​externas, tipos, macros e declarações de função em um arquivo de cabeçalho; fmin / fmax são declarados no arquivo de cabeçalho e, portanto, são expostos. Não tenho certeza do que você está se referindo como inseguro.
Racionalcoder

21

Esta é uma resposta tardia, devido a um desenvolvimento relativamente recente. Como o OP aceitou a resposta que se baseia em uma extensão GCC (e clang) não portátil typeof- ou __typeof__para ISO C 'limpo' - há uma solução melhor disponível a partir do gcc-4.9 .

#define max(x,y) ( \
    { __auto_type __x = (x); __auto_type __y = (y); \
      __x > __y ? __x : __y; })

O benefício óbvio dessa extensão é que cada argumento macro é expandido apenas uma vez, diferentemente da __typeof__solução.

__auto_typeé uma forma limitada de C ++ 11 auto. Ele não pode (ou não deveria?) Ser usado no código C ++, embora não haja uma boa razão para não usar os recursos superiores de inferência de tipo autoao usar o C ++ 11.

Dito isso, presumo que não há problemas ao usar essa sintaxe quando a macro é incluída em um extern "C" { ... }escopo; por exemplo, de um cabeçalho C. AFAIK, esta extensão não encontrou seu caminho. Info clang


Relacionado ao comentário de Brett Hale , clangcomeçou a oferecer suporte por __auto_typevolta de 2016 (consulte o patch ).
Lars

Kudos para reconhecer o problema macro, mas eu ainda postulam que uma função provavelmente seria melhor :-)
paxdiablo

@ paxdiablo - Eu concordo, embora a pergunta tenha a c-preprocessortag. Não é garantido que uma função seja incorporada, mesmo com a referida palavra-chave, a menos que seja usado algo como o __always_inline__atributo do gcc .
Brett Hale

11

Eu escrevi esta versão que funciona para MSVC, GCC, C e C ++.

#if defined(__cplusplus) && !defined(__GNUC__)
#   include <algorithm>
#   define MIN std::min
#   define MAX std::max
//#   define TMIN(T, a, b) std::min<T>(a, b)
//#   define TMAX(T, a, b) std::max<T>(a, b)
#else
#       define _CHOOSE2(binoper, lexpr, lvar, rexpr, rvar) \
                ({ \
                        decltype(lexpr) lvar = (lexpr); \
                        decltype(rexpr) rvar = (rexpr); \
                        lvar binoper rvar ? lvar : rvar; \
                })
#       define _CHOOSE_VAR2(prefix, unique) prefix##unique
#       define _CHOOSE_VAR(prefix, unique) _CHOOSE_VAR2(prefix, unique)
#       define _CHOOSE(binoper, lexpr, rexpr) \
                _CHOOSE2( \
                        binoper, \
                        lexpr, _CHOOSE_VAR(_left, __COUNTER__), \
                        rexpr, _CHOOSE_VAR(_right, __COUNTER__) \
                )
#       define MIN(a, b) _CHOOSE(<, a, b)
#       define MAX(a, b) _CHOOSE(>, a, b)
#endif

1
Voto a favor, mas os identificadores iniciados com um sublinhado e uma letra maiúscula são reservados.
dreamlax

8

Se você precisar de min / max para evitar uma ramificação cara, não use o operador ternário, pois ele será compilado até um salto. O link abaixo descreve um método útil para implementar uma função min / max sem ramificação.

http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax


1
Se o compilador é inteligente o suficiente ele pode evitar o ramo
Axel Gneiting

2
Se a otimização estiver ativada, todos os compiladores modernos emitirão uma movimentação condicional em vez de uma ramificação na maioria dos casos, portanto, há pouco sentido em usar hacks como este.
Krzysztof Kosiński

2
Absolutamente verdade, eu não tenho idéia do que eu estava olhando naquela época, já faz um tempo. O gcc e o clang evitam ramificações com -O, no x86 e no armv7a.
Cib

6

@ David Titarenco pregado-lo aqui , mas deixe-me pelo menos limpá-lo um pouco para torná-lo uma boa aparência, e mostrar tanto min() e max() em conjunto para fazer copiando e colando a partir daqui mais fácil. :)

Atualização 25 de abril de 2020: Eu também adicionei uma Seção 3 para mostrar como isso seria feito com os modelos C ++ também, como uma comparação valiosa para quem aprende C e C ++ ou faz a transição de um para o outro. Esforcei-me ao máximo para ser meticuloso, factual e correto, a fim de fazer desta resposta uma referência canônica para a qual posso voltar várias vezes, e espero que você a ache tão útil quanto eu.

1. A velha maneira macro C:

Essa técnica é comumente usada, respeitada por quem sabe usá-la adequadamente, a maneira "de fato" de fazer as coisas, e pode ser usada se usada corretamente, mas com erros (pense: efeito colateral de avaliação dupla ) se você sempre passe expressões incluindo atribuição de variáveis para comparar:

#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))

2. A nova e aprimorada maneira de " expressão de declaração " do gcc :

Essa técnica evita os efeitos colaterais e bugs da "dupla avaliação" acima e, portanto, é considerada o CCG superior, mais seguro e "mais moderno" maneira C do C para fazer isso. Espere que ele funcione com os compiladores gcc e clang, pois o clang é, por design, compatível com o gcc (consulte a nota do clang na parte inferior desta resposta).

MAS: Cuidado com os efeitos de " sombreamento variável " ainda, pois as expressões de instrução são aparentemente embutidas e, portanto, NÃO têm seu próprio escopo de variável local!

#define max(a,b)             \
({                           \
    __typeof__ (a) _a = (a); \
    __typeof__ (b) _b = (b); \
    _a > _b ? _a : _b;       \
})

#define min(a,b)             \
({                           \
    __typeof__ (a) _a = (a); \
    __typeof__ (b) _b = (b); \
    _a < _b ? _a : _b;       \
})

Observe que nas expressões de instrução gcc, a última expressão no bloco de código é o que é "retornado" da expressão, como se tivesse sido retornado de uma função. A documentação do GCC diz o seguinte:

A última coisa na declaração composta deve ser uma expressão seguida de ponto e vírgula; o valor dessa subexpressão serve como o valor de toda a construção. (Se você usar algum outro tipo de instrução por último entre chaves, a construção terá o tipo nulo e, portanto, efetivamente sem valor.)

3. A maneira do modelo C ++:

C ++ Nota: se estiver usando C ++, provavelmente os modelos são recomendados para esse tipo de construção, mas eu pessoalmente não gosto de modelos e provavelmente usaria uma das construções acima em C ++ de qualquer maneira, pois frequentemente uso e prefiro estilos C em C ++ incorporado.

Esta seção foi adicionada em 25 de abril de 2020:

Venho fazendo uma tonelada de C ++ nos últimos meses, e a pressão para preferir modelos em vez de macros, quando possível, na comunidade C ++ é bastante forte. Como resultado, estou aprimorando o uso de modelos e quero colocar aqui as versões do modelo C ++ para garantir a integridade e tornar essa resposta mais canônica e completa.

A seguir, quais são as versões básicas do modelo de funçãomax() e que min()podem parecer no C ++:

template <typename T>
T max(T a, T b)
{
    return a > b ? a : b;
}

template <typename T>
T min(T a, T b)
{
    return a < b ? a : b;
}

Faça leituras adicionais sobre modelos C ++ aqui: Wikipedia: Template (C ++) .

No entanto, ambos max()e min()já fazem parte da biblioteca padrão C ++, no <algorithm>cabeçalho ( #include <algorithm>). Na biblioteca padrão do C ++, eles são definidos de maneira ligeiramente diferente da que eu os tenho acima. Os protótipos padrão para std::max<>()e std::min<>(), por exemplo, no C ++ 14, observando seus protótipos nos links cplusplus.com logo acima, são:

template <class T> 
constexpr const T& max(const T& a, const T& b);

template <class T> 
constexpr const T& min(const T& a, const T& b);

Observe que a palavra typename- chave é um alias para class(portanto, seu uso é idêntico, independentemente de você dizer <typename T>ou não <class T>), já que mais tarde foi reconhecido após a invenção dos modelos C ++, que o tipo de modelo pode ser um tipo regular ( int,float , etc.) em vez de apenas um tipo de classe.

Aqui você pode ver que ambos os tipos de entrada, assim como o tipo de retorno, são const T&, o que significa "referência constante ao tipo T". Isso significa que os parâmetros de entrada e o valor de retorno são passados ​​por referência em vez de passados ​​por valor . É como passar por ponteiros e é mais eficiente para tipos grandes, como objetos de classe. A constexprparte da função modifica a própria função e indica que a função deve ser capaz de ser avaliada em tempo de compilação (pelo menos se houver constexprparâmetros de entrada fornecidos ), mas se não puder ser avaliada em tempo de compilação, o padrão será retornado para um avaliação em tempo de execução, como qualquer outra função normal.

O aspecto em tempo de compilação de uma constexprfunção C ++ o torna semelhante a macro-C, pois se a avaliação em tempo de compilação for possível para uma constexprfunção, ela será feita em tempo de compilação, o mesmo que um MIN()ouMAX() substituição de macro poderia possivelmente ser totalmente avaliado em tempo de compilação em C ou C ++ também. Para referências adicionais para essas informações de modelo C ++, consulte abaixo.

Referências:

  1. https://gcc.gnu.org/onlinedocs/gcc/Typeof.html#Typeof
  2. https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs
  3. MIN e MAX em C
  4. Referências adicionais ao modelo C ++ adicionadas em abril de 2020:
    1. ***** Wikipedia: Template (C ++) <- Ótimas informações adicionais sobre modelos de C ++!
    2. (Minha própria pergunta e resposta): Por que o `constexpr` faz parte do protótipo do modelo C ++ 14 para o` std :: max () `?
    3. Diferença entre `constexpr` e` const`

Nota da Wikipedia :

O [Clang] foi projetado para atuar como um substituto para o GNU Compiler Collection (GCC), suportando a maioria de seus sinalizadores de compilação e extensões de idioma não oficiais.


Para o downvoter das últimas 24 horas: boas notícias! Eu removi meu discurso da Seção 4 que adicionei ontem à Seção 3 e o coloquei aqui . Você pode reavaliar minha resposta e dar um voto positivo, se quiser, pois coloquei muitas informações boas e fiz o possível para torná-la uma resposta sólida, útil e canônica para beneficiar a todos. Agora está de volta ao foco. :) Obrigado!
Gabriel Staples

4

Vale ressaltar que acho que se você definir mine maxcom o terciário como

#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

para obter o mesmo resultado para o caso especial de fmin(-0.0,0.0)e fmax(-0.0,0.0)você precisa trocar os argumentos

fmax(a,b) = MAX(a,b)
fmin(a,b) = MIN(b,a)

Ainda não funcionará para NaN. fmin(3.0,NaN)==fmin(NaN,3.0)==fmax(3.0,NaN)==fmax(NaN,3.0)==3.0
Greggo

@greggo, eu dei uma resposta melhor aqui stackoverflow.com/a/30915238/2542702
Z boson

4

Parece que Windef.h(a la #include <windows.h>) possui maxe min(minúsculas) macros, que também sofrem com a dificuldade de "avaliação dupla", mas estão lá para aqueles que não querem relançar seus próprios :)


12
Você está surpreso?
Matt Joiner

2

Eu sei que o cara disse "C" ... Mas se você tiver a chance, use um modelo C ++:

template<class T> T min(T a, T b) { return a < b ? a : b; }

Digite safe e sem problemas com o ++ mencionado em outros comentários.


16
Os argumentos devem ser referências constantes, você nunca sabe o que o usuário passará.
nmikhailov

6
Essa função já foi padronizada ( std :: min ).
dreamlax

O C ++ possui muitas funções padrão para a maioria dos propósitos normais, não reinvente a roda. No entanto MS também define seu próprio min / max , que às vezes causa problemas
phuclv

0

O máximo de dois números inteiros ae bé (int)(0.5((a+b)+abs(a-b))). Isso também pode funcionar com (double)e fabs(a-b)para duplos (semelhante para carros alegóricos)


Desculpe se isso é errado, eu sou um novato C, mas este código funciona para mim
NRZ

2
Não tenho certeza se funciona com números não inteiros. A matemática de ponto flutuante possui precisão não linear.
precisa saber é o seguinte

Para expandir o comentário de @ Treesrule14: Isso não funciona porque os computadores não tratam os números da mesma maneira que os matemáticos. O ponto flutuante tem problemas de arredondamento, portanto, é improvável que você obtenha a resposta certa. Mesmo se você usar números inteiros, MAX_INT + MAX_INT fornece -2, então max (MAX_INT, MAX_INT) usando sua fórmula sairia como -1.
usar o seguinte comando

-3

A maneira mais simples é defini-la como uma função global em um .harquivo e chamá-la sempre que quiser, se o seu programa for modular com muitos arquivos. Caso contrário, double MIN(a,b){return (a<b?a:b)}é a maneira mais simples.


1
@technosaurus Seria útil se você descrevesse por que esta solução está errada, e não apenas.
precisa saber é o seguinte

@technosaurus, sua resposta é realmente inútil. Além disso, parece que a função está definida completamente incorreta (tipos ausentes nos parâmetros de entrada, ponto e vírgula ausente após a declaração de retorno) e converter entradas int em duplo é uma maneira ruim de fazer as coisas, portanto o tipo não deve ser duplo. Uma expressão de definição ou instrução seria melhor aqui (ex: veja aqui ), mas se uma função, considere criar uma função para fazer isso para os tipos int32_t, uma para os tipos uint32_t e uma para os tipos float ou double, para um total de 3 funções diferentes.
Gabriel Staples

1
@GabrielStaples Esta resposta deve ser sinalizada como não uma resposta - não há como ajudá-la. Embora possa ser usado como um exemplo de como estar o mais errado na menor quantidade de espaço. A recomendação de funções globais em um cabeçalho (nem sequer estático em linha estático?) Quebrará o código com mais de 2 unidades de compilação, nem compila, nomeando uma função como uma macro, entradas implícitas como a de 1989, retornando um duplo sem motivo declarado, implícita elencos que irão causar avisos no melhor ... e mais importante não responde a pergunta - não genérica, não tipo seguro e mais definitivamente não é a melhor maneira
Technosaurus

Cada um desses problemas merece críticas adicionais que não podem ser abordadas em detalhes suficientes.
Technosaurus # 28/19
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.