Função recebe 2 textos iguais, mas trata eles de forma diferente !? [RESOLVIDO]

13. Re: Função recebe 2 textos iguais, mas trata eles de forma diferente !? [RESOLVIDO]

Samuel Leonardo
SamL

(usa XUbuntu)

Enviado em 01/02/2023 - 01:55h

O único modo que vejo de desbloquear e ter certeza de que não é uma meórmia constante é criar uma nova string com malloc do mesmo tamanho do texto passado no change. Seria algo como duplicar a string, o problema que vejo é que precisa liberar a memória dela.

A não ser é claro que tu faça o seguinte:
1-dentro de change, aloca um ptr do mesmo tamanho de Text
2-copia o conteúdo de text para o ptr alocado
3-modifica somente o ptr, onde tu quer modificar e imprime no terminal com puts
4-desaloca o ptr e retorna de change

Acho que isso é o mais simples a se fazer em C.

https://nerdki.blogspot.com/ acessa ai, é grátis
Não gostou? O ícone da casinha é serventia do site!


  


14. Re: Função recebe 2 textos iguais, mas trata eles de forma diferente !?

Paulo
paulo1205

(usa Ubuntu)

Enviado em 01/02/2023 - 02:00h

Eu já expliquei isso um bocado de vezes, acho que inclusive para você. Mas como eu mesmo não encontrei essas mensagens na busca do fórum, explico de novo.


Antes de falar do C, deixe-me falar do C++, que é um pouco mais são nesse ponto.

Em C++, constantes literais de strings são expressas entre aspas (ou outras formas mais complexas, mas não vem ao caso aqui), e provocam a criação de um array de caracteres constantes (const char) com tantos elementos quanto caracteres entre as aspas, mais um elemento ao final para acomodar o byte nulo que funciona como terminador da string. Isso está na §2.14.5 do padrão do C++ de 2011 (https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf), e na §5.13.5 tanto no padrão de 2017 (https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf) quanto no de 2020 (https://isocpp.org/files/papers/N4860.pdf).

Entendo que isso faz todo o sentido: se é uma constante literal de string, é muito razoável que o tipo de dados associado ao array criado para armazenar tal constante tenha elementos constantes.

Quase que dá vontade de falar “duh!” depois de repetir tantas vezes a palavra “constante” na mesma frase, não?

Pois é... Mas isso é em C++.


O C, por outro lado, optou por não considerar o tipo de dados gerado a partir de uma constante literal de strings como um array com elementos constantes. Em vez disso, o tipo de dados associado a constantes literais de strings em C é array de caracteres comuns (apenas char) com tantos elementos quanto houver entre as aspas, mais um elemento para acomodar o byte nulo que termina a strings. ENTRETANTO, apesar de o tipo de dado de cada elemento do array ser char (não-constante), o padrão da linguagem abre espaço para que as implementações armazenem tais o conteúdo desses arrays provenientes de constantes literais strings em memória que seja somente de leitura — afinal, trata-se de constantes literais! — ao dizer que a tentativa de modificar uma dessas constantes provoca comportamento indefinido (§6.4.5 do padrão do C de 2011 (https://port70.net/~nsz/c/c11/n1570.pdf)).

Aparentemente, o que motivou essa escolha por parte do comitê de padronização do C foi não introduzir incompatibilidade com código antigo que fazia (como eu fiz no passado, e você faz ainda hoje) declarações com inicialização tais como
char *str="Alguma coisa."; 
, que é algo que vem acompanhando o C praticamente desde seu início como linguagem, numa época em que, entre outras coisas, a palavra-chave const ainda não havia sido criada, e ainda era comum usar o C em arquiteturas que não contavam com proteção contra escrita em certas regiões de memória.


Ninguém me perguntou, mas eu acho essa solução de compromisso péssima, quase que a pior possível. Conquanto eu valorize manter a compatibilidade com código antigo, essa ideia de permitir gravar em memória não-alterável um dado de um tipo que não carrega nenhuma indicação de ser somente para leitura uma armadilha para o programador — não apenas para alguém ainda próximo do estágio de novato, como você, mas também para programadores experientes. No seu caso, imagino que você tenha usado os mecanismos do compilador para diagnóstico de código inseguro (no GCC, as opções de compilação -Wextra, -Werror e -pedantic-errors), mas mesmo assim nenhum diagnóstico foi emitido, porque o tipo de dados prescrito pelo padrão e seguido pela implementação, por si só, não permite ao compilador a fazer tal diagnóstico.


O GCC até tem como emitir alerta a respeito desse problema, mas, para tanto, ele tem de fugir do que diz o padrão da linguagem C, alterando o tipo resultante de uma constante literal de string de char [N+1] (onde N é o número de caracteres entre aspas) para const char [N+1], como é em C++. Para habilitar essa alteração, a opção a ser usada é -Wwrite-strings.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)


15. Re: Função recebe 2 textos iguais, mas trata eles de forma diferente !?

Apprentice X
ApprenticeX

(usa FreeBSD)

Enviado em 01/02/2023 - 02:51h

paulo1205 escreveu: O GCC até tem como emitir alerta a respeito desse problema, mas, para tanto, ele tem de fugir do que diz o padrão da linguagem C, alterando o tipo resultante de uma constante literal de string de char [N+1] (onde N é o número de caracteres entre aspas) para const char[N+1], como é em C++. Para habilitar essa alteração, a opção a ser usada é -Wwrite-strings.

Confuso mesmo! Fiz uns testes baseados na sua resposta.

Compilando em c++ ele avisa do erro!
g++ test.cpp -o test -march=native -Ofast -Wextra -pedantic -pedantic-errors -Werror
error: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]

Modificando a função para const
void Change(const char *Text) {

error: assignment of read-only location '*(Text + 5)'

Conforme sua instrução em adicionar -Wwrite-strings em C
gcc test.c -o test -march=native -Ofast -Wextra -pedantic -pedantic-errors -Werror -Wwrite-strings
Porém a informação do erro não é tão esclarecedor qto a de c++
error: passing argument 1 of 'Change' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]

Modificando a função para const
void Change(const char *Text) {

error: assignment of read-only location '*(Text + 5)'
Passarei a adicionar -Wwrite-strings ao compilar em C
Ainda estou me familiarizando com o que deve ou não ser constante.
Mas intriga o fato que de uma forma geral, a maioria dos valores são variáveis! Fico pensando, se passo um valor para uma variável, subentende-se que ele vai variar!

Por isso acho intrigante, o compilador armazenar um valor constante, sem saber se ele será ou não constante! Ou seja, ele decidiu por conta própria que os dados que passei são constantes e que eu não os mudaria, mesmo eu informando que minha função não é constante void Change(char *Text)

Não sei se estou errado, mas com meu pouco conhecimento, me parece que quem está programando é o compilador neste caso! Eu criei uma função não-constante! Passo um dado para minha função que não deveria ser constante, pq em momento algum, eu disse ao meu programa que estou trabalhando com valores constantes! MAS o Compilador do Supremo, decidiu sem me consultar que é constante e pronto! É estranho!

Talvez exista um motivo pra colocarem essa situação como constante, mas sai um pouco da lógica qdo trabalhamos com variáveis, são variáveis pq obviamente a todo instante estamos variando seus valores por um ou outro motivo. No meu caso, eu apenas enviei uma string a um ponteiro, que compreendo ele ao invés de armazenar um outro local da memória não constante e apontar para lá, o que ocorreu foi ele apontar para o local onde o compilador por conta própria salvou como constante

Ponto curioso é que mesmo usando: gcc test.c -o test -std=c89
Ele dá o problema, o que significa que o compilador aparentemente SEMPRE salvou como constante desde aquela 1989 acredito

Mas tudo bem, é bom conhecer todas essas informações, e entender como funciona tudo isso!


16. Re: Função recebe 2 textos iguais, mas trata eles de forma diferente !? [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 04/02/2023 - 06:27h

ApprenticeX escreveu:

paulo1205 escreveu: O GCC até tem como emitir alerta a respeito desse problema, mas, para tanto, ele tem de fugir do que diz o padrão da linguagem C, alterando o tipo resultante de uma constante literal de string de char [N+1] (onde N é o número de caracteres entre aspas) para const char[N+1], como é em C++. Para habilitar essa alteração, a opção a ser usada é -Wwrite-strings.

Confuso mesmo! Fiz uns testes baseados na sua resposta.

Compilando em c++ ele avisa do erro!
g++ test.cpp -o test -march=native -Ofast -Wextra -pedantic -pedantic-errors -Werror
error: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]

Modificando a função para const
void Change(const char *Text) {


Alterar o tipo do parâmetro para poder receber uma string constante não parece fazer muito sentido aqui, já que a função tem o nome de “change”. O certo seria você, como programador, garantir que o objeto que você vai passar como argumento pode realmente ser alterado.

Conforme sua instrução em adicionar -Wwrite-strings em C


Não foi instrução. Foi apenas uma informação de como obter o diagnóstico, pagando o preço de fazer o compilador alterar o tipo de dados da string (para aquilo que deveria ser o tipo certo desde o início, na minha opinião...).

gcc test.c -o test -march=native -Ofast -Wextra -pedantic -pedantic-errors -Werror -Wwrite-strings
Porém a informação do erro não é tão esclarecedor qto a de c++
error: passing argument 1 of 'Change' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]


Engraçado... Eu acho até mais esclarecedora.

Passarei a adicionar -Wwrite-strings ao compilar em C
Ainda estou me familiarizando com o que deve ou não ser constante.


Uma constante literal não me parece deixar muita dúvida.

Mas intriga o fato que de uma forma geral, a maioria dos valores são variáveis! Fico pensando, se passo um valor para uma variável, subentende-se que ele vai variar!


Apesar do nome, nem toda variável varia. Se você disse que o tipo de dados de uma variável é constante (por exemplo: const int, const double ou mesmo void *const), ela continuará sendo classificada como variável, de acordo com a nomenclatura dos padrões do C e do C++, mas frequentemente o compilador vai tomar medidas para que seus valores não possam ser alterados.

Além disso, eu não sei se você está com a visão correta sobre algumas características da linguagem.

Em particular, quando você tem funções em C, a passagem de argumentos é sempre por valor — ou, como eu costumo falar, na expectativa de deixar ainda mais claro, por cópia de valor. Isso significa que quando você chama uma função em alguma parte do seu programa, os valores dos argumentos passados à função são calculados e copiados para os respectivos parâmetros da função.

Isso implica que o programa
#include <stdio.h>

int f(int x, int y){
x+=5;
y*=2;
return x+y;
}

int main(void){
int a=0;
int r=f(a, 3);
printf("a=%d; r=%d\n", a, r);
}
vai imprimir como saída “a=0; r=11”, e vai funcionar da seguinte forma (num PC de 32 bits†):

    • Ao iniciar a execução em main(), será alocado espaço para avariável a, e nele será guardado o valor 0.

    • Será alocado espaço para a variável r, e o valor atribuído a ela dependerá da invocação da função f(), o que é feito do seguinte modo:

        • Para invocar f(), o compilador primeiro faz uma cópia do valor da constante literal 3 para a pilha do processador.

        • Em seguida, o valor de a (que é 0) é lido do local em que é armazenado, e é feita uma cópia dele na pilha do processador.

        • A função f() é invocada.

    • Uma vez dentro de f, o que acontece é o seguinte:

        • O último argumento colocado na pilha é associado ao parâmetro x e o penúltimo argumento colocado na pilha ao valor de y (no nosso caso, portanto, x tem, por enquanto, uma cópia do valor de a (que é 0), e y tem o valor 3).

        • O valor de x, que está guardado na pilha, é incrementado em 5 (passando, portanto, a valer 5).

        • O valor de y, que também está guardado na pilha, é multiplicado por 2 (passando, portanto, a valer 6).

        • Os valores de x (5) e de y (6) são somados (resultando em 11) e colocados no acumulador (registrador EAX do processador), que é convencionalmente a forma de indicar o valor de retorno da função.

        • A função retorna ao ponto em que foi chamada.

    • Após o retorno da função f(), o espaço que havia sido usado na pilha para copiar os argumentos é devolvido (isto é: soma-se sizeof x + sizeof y ao indicador do topo da pilha).

    • O valor de retorno da função (11), que ainda está no acumulador, é copiado para a variável local r.

    • Através da chamada a printf(), os valores de a (que ainda vale 0) e de r) são impressos, de acordo com a string de formatação da saída.

O que eu desejo que fique claro com a ilustração acima é que ocorre dentro da função não afeta aquilo que foi usado como argumento, porque aquilo que a função recebe em seus parâmetros é apenas uma cópia do que quer que tenha sido usado como argumentos. A função até pode alterar esses parâmetros, mas como eles estão fisicamente separados dos argumentos usados para produzir seus valores originais, tais alterações seguramente não vão alterar esses originais.

Entretanto, uma possibilidade que o uso de ponteiros oferece é poder chegar a um dado original mesmo quando o programa tem um desvio de fluxo no qual aquele dado não estaria visível, tal como quando uma função é invocada. Ao se copiar o mesmo endereço de um determinado dado N vezes, todas as N cópias podem ser usada para chegar ao mesmo dado.

Essa é, aliás, uma das razões pelas quais o uso de ponteiros em C é tão importante e tão aparentemente mais frequente do que em outras linguagens. Em C, se você quiser, por exemplo, que uma função tenha acesso a um objeto que foi declarado fora dela, e não simplesmente a uma cópia desse objeto, não adianta tentar passar tal objeto como argumento diretamente, já que argumentos de funções são sempre copiados; entretanto, se você passar como argumento uma cópia do endereço no qual tal objeto reside, é evidente que essa cópia do endereço pode ser usada para chegar ao mesmo objeto.

Outras linguagens têm mecanismos para especificar quando o parâmetro de uma função deve receber cópias dos valores do argumentos (passagem de argumentos por valor) ou quando devem poder ser manipulados diretamente por essas funções, tipicamente através de passagem de argumentos por referência. Eis alguns exemplos completamente equivalentes em Pascal e em C++ de programas que imprimem como saída o valores 5 6, obtidos a partir de duas variável inicialmente definidas com valor 5, mas com uma delas sendo passada a uma função por valor, e outra passada a outra função por referência.
{ Código em Pascal }
program x;

procedure p1(n: integer);
begin
n:=succ(n);
end;

procedure p2(var n: integer);
begin
n:=succ(n);
end;

var m, n: integer;

begin
m:=5; n:=5;
p1(m);
p2(n);
writeln(m, ' ', n);
end.
// Código em C++
#include <iostream>

void p1(int n){
++n;
}

void p2(int &n){
++n;
}

int main(){
int m=5, n=5;
p1(m);
p2(n);
std::cout << m << ' ' << n << '\n';
}


Uma curiosidade de ambos os programas acima é que as chamadas p1(m) e a p2(n) são visualmente muito parecidas: em ambas, o argumento é simplesmente uma variável, sem nada que indique que a primeira usa passagem por valor e a segunda usa passagem por referência. Em ambos os casos, o programador tem de conhecer a semântica das funções para saber quem pode modificar o valor do argumento ou não (neste caso, é simples olhar a implementação de cada função nos corpos dos programas; entretanto, num caso geral, o programa pode ser muito longo, dificultando olhar outras partes, ou mesmo usar uma bibliotecas externas, às quais o leitor do código poderia não ter acesso para inferir qual tipo de passagem de argumentos é usada).

C, por sua vez, simplesmente não possui passagem de argumentos por referência, mas apenas por valor. Assim sendo, se você quiser o efeito de poder modificar um objeto declarado fora de uma função, tem de escrever a função de modo a explicitamente receber (uma cópia de) o endereço do objeto a ser modificado, e, ao chamar a função, você tem de explicitamente obter o endereço do objeto. Assim sendo, a forma de escrever uma versão em C dos programas acima seria a seguinte.
#include <stdio.h>

void p1(int n){
++n;
}

void p2(int *n){ // Recebo uma cópia do endereço (ponteiro) para o objeto.
++*n; // Explicito que quero incrementar o conteúdo apontado pelo parâmetro (“*n”), não meramente o parâmetro em si mesmo.
}

int main(){
int m=5, n=5;
p1(m);
p2(&n); // Indicação explícita de que se está passando um endereço (“&n” produz um ponteiro (ou referência) para o dado representado por n).
printf("%d %d\n", m, n);
}


A grande diferença está já realçada nos comentários: na falta de um mecanismo de passagem por referência, o programa em C é forçado obter referências explícitas para os dados que têm de ser alterados e usar essas referência explícitas como argumentos, que são passados por valor (isto é: são copiados) para as funções,que, por sua vez, são obrigadas a usar argumentos com tipos de dado que são ponteiros a fim de receber (por valor, ou seja, cópias) os endereços dos objetos e a indicar também explicitamente cada vez que quiserem manipular o conteúdo apontado, em lugar de apenas o parâmetro em si.

Cada forma de fazer tem suas vantagens e desvantagens aparentes: as de Pascal e de C++ são visualmente mais simples, mas dão margem a confusão na hora de ler o código (principalmente para quem o lê pela primeira vez, ou volta a ele depois de muito tempo sem vê-lo); já em C, ter de usar um & antes do nome do objeto já serve como sinal de que a função pode vir a alterar o valor desse objeto, mas também obriga o programador a escrever um pouco a mais de código. Entretanto, não existe mágica: as três versões são rigorosamente equivalentes, e é bem provável que, exceto pelo momento de escrever a saída final, os códigos executáveis das três sejam extremamente parecidos, se não completamente idênticos.


OK. Falei um monte de coisa e dei exemplos que eu espero que tenham sido claros, mas todos eles foram com tipos de dados simples, não com tipos compostos.

No caso em questão, temo que você esteja achando, quer pelo seu entendimento anterior, quer depois de minha insistência, acima, de que a passagem de argumentos em C é sempre por (cópia de) valor, que algo como puts("Esta é uma string"); passaria uma cópia de todos os caracteres da string para dentro da função. Não é o caso, porque o tipo de "Esta é uma string" é array com 18 elementos do tipo char (supondo codificação UTF-8, na qual o caráter “é” ocupa dois bytes), e, sendo um array usado numa expressão que espera um rvalue, ele decai automaticamente para um ponteiro para seu primeiro elemento (§6.3.2.1, parágrafo 3 do padrão do C de 2011; §7.3.2 do padrão de 2020 do C++). Assim sendo, a cópia de valor do argumento é tão-somente desse endereço do primeiro elemento, não é do conteúdo do array.

Então quando a sua função original Change() é chamada com uma constante literal de string, ela recebe o endereço de um array que é constante, e quando ela usa o endereço para alterar um elemento indexado a partir desse endereço, vai tentar alterar uma posição de memória que é, na prática, constante, e isso causa a falha de segmentação.

Por isso acho intrigante, o compilador armazenar um valor constante, sem saber se ele será ou não constante!


O compilador sabe que é constante, sim. Mas o padrão do C manda (e, como eu disse em outra mensagem, eu discordo radicalmente dessa escolha) que o sistema de tipos não carregue a informação de que é constante. Tanto o compilador sabe, que, quando você usa aquela opção -Wwrite-strings, ele ignora o mandato do padrão do C a esse respeito, plenamente considerando o tipo dos elementos como constantes.

Uma abordagem que eu recomendo é a seguinte: prefira C++ em lugar do C.

Ou seja, ele decidiu por conta própria que os dados que passei são constantes e que eu não os mudaria, mesmo eu informando que minha função não é constante void Change(char *Text)


Não é por conta própria. Como eu expliquei anteriormente, o padrão permite que constantes literais de strings sejam alocadas em memória que não possa ser posteriormente alterada, e o compilador faz isso porque fazê-lo tem diversas vantagens (de cara, o fato de que uma string que é uma constante literal parece tornar muito adequado seu armazenamento em memória que seja inalterável; mas há outras potenciais vantagens, tais como permitir reutilizar a totalidade ou partes desse mesmo array para outras strings que ocorram ao longo do programa, a fim de economizar espaço). O problema todo é o conflito entre essa permissão vantajosa e o tipo de dados não-constante que é preferido em função de manter compatibilidade com código antigo.

E parte do problema é também o fato de você não conhecer esses detalhes sobre a linguagem. Contudo, entendo que você, por estar começando, tem o direito de errar, e o fato de você ter cometido esse erro abriu a porta para o aprendizado, através desta discussão realizada aqui.

Não sei se estou errado, mas com meu pouco conhecimento, me parece que quem está programando é o compilador neste caso!


Discordo. O compilador está seguindo à risca as regras da linguagem que você se propôs a usar. Quem não as seguiu, por não as conhecer, foi você.

Se as regras referentes a esse aspectos são estapafúrdias, é outra discussão.

Eu criei uma função não-constante! Passo um dado para minha função que não deveria ser constante, pq em momento algum, eu disse ao meu programa que estou trabalhando com valores constantes!


Eu diria que uma constante literal deveria ser constante, sim.

Se você não quer que ela seja constante, então não deve usar uma constante literal, mas sim um array. Você, aliás, fez isso duas linhas acima, quando declarou o array Text, com tipo de caracteres não-constante (note que, naquela declaração, o texto entre aspas não é uma constante literal, mas sim uma representação dos valores iniciais do array não constante (i.e. cujos elementos não são constantes) que está sendo declarado. Apenas recapitulando, mas com comentários explicativos, compare as duas linhas no seguinte código.
    char text[]="Teste";  // O array ‘text’ não é constante, e este texto entre as aspas representa os elementos iniciais do array.
char *ptr="Teste"; // Este texto entre aspas é uma constante literal de strings, que pode ser (e geralmente é) alocado em memória somente de leitura
// Atribuí-lo a (ou passá-lo como argumento para uma função com um parâmetro que seja) um ponteiro para dados não constantes é
// um risco, mas é algo que o padrão do C diz que tem de ser assim. Com -Wwrite-strings (ou em C++, que tem regras diferentes do C),
// esta segunda linha provocaria erro.


MAS o Compilador do Supremo, decidiu sem me consultar que é constante e pronto! É estranho!


Nada disso! Você que começou a usar uma ferramenta que não entendia totalmente — a linguagem C — e que tem umas idiossincrasias não intuitivas.

De novo meu conselho: prefira C++.

Talvez exista um motivo pra colocarem essa situação como constante, mas sai um pouco da lógica qdo trabalhamos com variáveis, são variáveis pq obviamente a todo instante estamos variando seus valores por um ou outro motivo. No meu caso, eu apenas enviei uma string a um ponteiro, que compreendo ele ao invés de armazenar um outro local da memória não constante e apontar para lá, o que ocorreu foi ele apontar para o local onde o compilador por conta própria salvou como constante


Como dito acima, o motivo é compatibilidade com código antigo, de uma época em que não havia a palavra-chave const nem o atributo que ela designa. Não tem vontade nem conta própria do compilador interferindo com seu código: tem uma regra que faz parte da definição da linguagem, que o compilador simplesmente está seguindo.

Também já falei (eu acho) sobre a questão de terminologia. O conceito de variável em programação não é necessariamente exatamente o mesmo que tem em matemática. Grosseiramente falando, em programação, variável é uma notação de um objeto que representa um dado de um determinado tipo. Ponto. Se o tipo do dado representado tem um atributo que o faz constante, o valor dessa variável, depois de inicializado, não vai poder ser alterado, e, para tanto, o compilador vai tomar medidas para que evitar que você viole esse atributo do dado (inclusive, eventualmente, armazenando-o numa memória protegida contra escrita). Mas, tirando esses cuidados, do ponto de vista de funcionamento (como dispor em memória, qual a quantidade de memória ocupada, como fazer acessos, como converter para outros tipos, etc.), uma variável “comum” e uma que não pode ser alterada são parecidas demais para serem chamadas de nomes distintos.

Além disso, note o seguinte: na declaração
const char *nome="ApprenticeX"; 
a variável nome não é constante — o que é constantes são os dados para os quais ela aponta. Compare as seguintes declarações.
char ac[]="Teste";		// Array com 6 caracteres não-constantes.
const char acc[]="Teste"; // Array com 6 caracteres constantes.
char *pc=ac; // Ponteiro não-constante para caracteres não-constantes.
const char *pcc=acc; // Ponteiro não-constante para caracteres constantes.
char *const cpc=ac; // Ponteiro constante para caracteres não-constantes.
const char *const cpcc=acc; // Ponteiro constante para caracteres constantes.


Ponto curioso é que mesmo usando: gcc test.c -o test -std=c89
Ele dá o problema, o que significa que o compilador aparentemente SEMPRE salvou como constante desde aquela 1989 acredito


Errado. Se você reparar na mensagem de erro dessa compilação, verá que o erro se refere ao fato de que o C89 não aceitava comentários iniciados por //. Não tem nada a ver com usar ponteiros para dados não-constantes para referir-se a constantes literais de strings.

----

† Eu descrevi a chamada de função típica em plataforma Intel de 32 bits (i386) porque ela é (ou era) bem conhecida e relativamente uniforme (havia variações, mas não eram tão comuns assim) entre vários sistemas operacionais diferentes (desde a época do 8086, de 16 bits, na verdade). Nossos sistemas de 64 bits (amd64 ou x86-64) são menos uniformes a esse respeito, com o mundo UNIX usando uma convenção diferente do Windows: ambos preferem passar dados através de registradores, em vez de usar somente a pilha, mas a quantidade, o conjunto e a ordem dos registradores em cada um desses mundos é diferente, assim como são diferentes os critérios para usar a pilha, quer seja quando os registradores não são suficientes para armazenar todos os parâmetros, quer porque os tipos dos parâmetros não permitem o uso de registradores.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)



01 02



Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts