Guia de rastreamento dinâmico Solaris

Capítulo 2 Tipos, operadores e expressões

D fornece o recurso de acessar e manipular uma variedade de objetos de dados: variáveis e estruturas de dados podem ser criadas e modificadas, objetos de dados podem ser definidos no kernel do sistema operacional, processos do usuário podem ser acessados e constantes de inteiro, de ponto flutuante e de seqüência podem ser declaradas. D fornece um superconjunto dos operadores ANSI-C usados para manipular objetos e criar expressões. Este capítulo descreve o conjunto detalhado de regras de tipos, operadores e expressões.

Nomes e palavras-chave do identificador

Os nomes de identificador de D são compostos de letras maiúsculas e minúsculas, dígitos e sublinhados, onde o primeiro caractere deve ser uma letra ou sublinhado. Todos os nomes de identificador que começam com um sublinhado (_) são reservados para serem usadas pelas bibliotecas do sistema D. Você deve evitar o uso de tais nomes em seus programas em D. Por convenção, os programadores de D geralmente usam nomes com letras maiúsculas e minúsculas para variáveis e todas as letras maiúsculas para constantes.

As palavras-chave da linguagem D são identificadores especiais reservados para serem usados na própria sintaxe da linguagem de programação. Esses nomes são sempre especificados em letra minúscula e talvez não sejam usados nos nomes de variáveis de D.

Tabela 2–1 Palavras-chave de D

auto*

goto*

sizeof

break*

if*

static*

case*

import*+

string+

char

inline

stringof+

const

int

struct

continue*

long

switch*

counter*+

offsetof+

this+

default*

probe*+

translator+

do*

provider*+

typedef

double

register*

union

else*

restrict*

unsigned

enum

return*

void

extern

self+

volatile

float

short

while*

for*

signed

xlate+

D reserva para uso como palavras-chave um superconjunto de palavras-chave ANSI-C. As palavras-chave reservadas para uso futuro pela linguagem D são marcadas com “*”. O compilador de D produzirá um erro de sintaxe, se você tentar usar uma palavra-chave que esteja reservada para uso futuro. As palavras-chave definidas por D mas não definidas por ANSI-C são marcadas com “+”. D fornece o conjunto completo de tipos e operadores encontrado em ANSI-C. A diferença principal na programação em D é a ausência de construções de fluxo de controle. Palavras-chave associadas ao fluxo de controle em ANSI-C são reservadas para uso futuro em D.

Tipos e tamanhos de dados

D fornece tipos de dados fundamentais para constantes de inteiro e de ponto flutuante. A aritmética só pode ser realizada em inteiros em programas em D. As constantes de ponto flutuante podem ser usadas para inicializar estruturas de dados, mas a aritmética de ponto flutuante não é permitida em D. D fornece modelos de dados de 32 e 64 bits para serem usados na criação de programas. O modelo de dados usado quando você executa o seu programa é o modelo de dados nativo associado ao kernel do sistema operacional ativo. Você pode determinar o modelo de dados nativo do sistema usando isainfo -b.

Os nomes dos tipos inteiros e seus tamanhos em cada um dos dois modelos de dados são mostrados na tabela seguinte. Os inteiros são sempre representados no formato de dois complementos na ordem de codificação de byte nativa do sistema.

Tabela 2–2 Tipos de dados inteiros de D

Nome de tipo 

Tamanho 32–bit 

Tamanho 64–bit 

char

1 byte 

1 byte 

short

2 bytes 

2 bytes 

int

4 bytes 

4 bytes 

long

4 bytes 

8 bytes 

long long

8 bytes 

8 bytes 

Tipos inteiros podem ser prefixados com o qualificador signed ou unsigned . Se não houver qualificador de sinal, o tipo é presumidamente assinado. O compilador de D também fornece os alias de tipo listados na tabela seguinte:

Tabela 2–3 Alias de tipo inteiro de D

Nome de tipo 

Descrição 

int8_t

Inteiro assinado de 1 byte 

int16_t

Inteiro assinado de 2 bytes 

int32_t

Inteiro assinado de 4 bytes 

int64_t

Inteiro assinado de 8 bytes 

intptr_t

Inteiro assinado do tamanho de um ponteiro 

uint8_t

Inteiro não assinado de 1 byte 

uint16_t

Inteiro não assinado de 2 bytes 

uint32_t

Inteiro não assinado de 4 bytes 

uint64_t

Inteiro não assinado de 8 bytes 

uintptr_t

Inteiro não assinado do tamanho de um ponteiro 

Esses alias de tipo são equivalentes a usar o nome do tipo base correspondente na tabela anterior e são definidos apropriadamente para cada modelo de dados. Por exemplo, o nome de tipo uint8_t é um alias do tipo unsigned char. Consulte o Capítulo 8Definições de tipo e de constante para obter informações sobre como definir seus próprios alias de tipo a serem usados em seus programas em D.

D fornece tipos de ponto flutuante para compatibilidade com declarações e tipos ANSI-C. Operadores de ponto flutuante não são aceitos em D, mas objetos de dados de ponto flutuante podem ser rastreados e formatados por meio da função printf() . Os tipos de ponto flutuante listados na tabela seguinte podem ser usados:

Tabela 2–4 Tipos de dados de ponto flutuante de D

Nome de tipo 

Tamanho 32–bit 

Tamanho 64–bit 

float

4 bytes 

4 bytes 

double

8 bytes 

8 bytes 

long double

16 bytes 

16 bytes 

D também fornece o tipo especial string para representar as seqüências ASCII. As seqüências são discutidas em mais detalhes no Capítulo 6Seqüências.

Constantes

Constantes de inteiro podem ser escritas em decimal (12345), octal (012345) ou hexadecimal (0x12345). Constantes octais (base 8) devem ser prefixadas com um zero à esquerda. Constantes hexadecimais (base 16) devem ser prefixadas com 0x ou 0X. Os menores tamanhos são atribuídos a constantes de inteiro entre int, long e long long que podem representar seu valor. Se o valor for negativo, a versão assinada do tipo será usada. Se o valor for positivo e muito grande para caber na representação de tipo assinado, a representação de tipo não assinado será usada. Você pode aplicar um dos seguintes sufixos a uma constante inteira para especificar explicitamente seu tipo D:

u ou U

Versão unsigned do tipo selecionado pelo compilador

l ou L

long

ul ou UL

unsigned long

ll ou LL

long long

ull ou ULL

unsigned long long

Constantes de ponto flutuante são sempre escritas em decimal e devem conter um ponto decimal (12.345) ou um expoente ( 123e45) ou ambos (123.34e-5). O tipo double é atribuído por padrão às constantes de ponto flutuante. Você pode aplicar um dos seguintes sufixos a uma constante inteira para especificar explicitamente seu tipo D:

f ou F

float

l ou L

long double

Constantes de caractere são escritas como um único caractere ou seqüência de escape entre um par de aspas simples ('a'). O tipo int é atribuído às constantes de caractere, que são equivalentes a uma constante inteira cujo valor é determinado pelo valor desse caractere no conjunto de caracteres ASCII. Você pode consultar ascii(5) para obter uma lista de caracteres e seus valores. Você também pode usar qualquer uma das seqüências de escape especiais mostradas na tabela seguinte em suas constantes de caractere. D aceita as mesmas seqüências de escape encontradas em ANSI-C.

Tabela 2–5 Seqüências de escape de caractere de D

\a

alerta 

\\

retroreferência 

\b

backspace 

\?

ponto de interrogação 

\f

alimentação de formulário 

\'

aspas simples 

\n

nova linha 

\”

aspas duplas 

\r

retorno de carro 

\0oo

valor octal 0oo

\t

guia horizontal 

\xhh

valor hexadecimal 0xhh

\v

guia vertical 

\0

caractere nulo 

Você pode incluir mais de um especificador de caractere entre aspas simples para criar inteiros cujos bytes individuais são inicializados de acordo com os especificadores de caractere correspondentes. Os bytes são lidos da esquerda para a direita da constante de caractere e atribuídos ao inteiro resultante na ordem correspondente ao endian-ness nativo do seu sistema operacional. Até oito especificadores de caractere podem ser incluídos em uma única constante de caractere.

As constantes de seqüências de qualquer tamanho podem ser compostas quando colocadas entre um par de aspas duplas ("olá"). Uma constante de seqüência talvez não contenha um caractere de nova linha literal. Para criar seqüências que contêm novas linhas, use a seqüência de escape \n em vez de uma nova linha literal. As constantes de seqüência podem conter qualquer de uma das seqüências de escape de caractere especial mostradas acima para constantes de caractere. Semelhante ao ANSI-C, as seqüências são representadas como matrizes de caracteres terminadas por um caractere nulo (\0), que é implicitamente adicionado a cada constante de seqüência que você declarar. O tipo D especial string é atribuído às constantes de seqüência. O compilador de D fornece um conjunto de recursos especiais para comparar e rastrear as matrizes de caracteres que são declaradas como seqüências, conforme descrito no Capítulo 6Seqüências.

Operadores aritméticos

D fornece os operadores aritméticos binários mostrados na tabela seguinte a serem usados em seus programas. Todos esses operadores possuem o mesmo significado para inteiros, como acontece em ANSI-C.

Tabela 2–6 Operadores aritméticos de D

+

adição de inteiro 

-

subtração de inteiro 

*

multiplicação de inteiro 

/

divisão de inteiro 

%

módulo de inteiro 

A aritmética em D só pode ser realizada em operandos de inteiro, ou em ponteiros, como discutido no Capítulo 5Ponteiros e matrizes. A aritmética pode ser realizada em operandos de ponto flutuante em programas em D. O ambiente de execução do DTrace não precisa realizar nenhuma ação de estouro positivo ou de estouro negativo de inteiro. Você mesmo deve verificar essas condições em situações em que o estouro positivo e negativo podem ocorrer.

O ambiente de execução do DTrace não verifica e reporta automaticamente os erros de divisão por zero resultantes do uso incorreto dos operadores / e % . Se um programa em D executar uma operação de divisão inválida, o DTrace desativará automaticamente a instrumentação afetada e reportará o erro. Os erros detectados por DTrace não têm efeito em outros usuários de DTrace ou no kernel do sistema operacional, sendo assim, você não precisa se preocupar em causar nenhum dano se o seu programa inadvertidamente contiver um desses erros.

Além desses operadores binários, os operadores + e - também podem ser usados como operadores unários; esses operadores têm maior precedência do que quaisquer operadores aritméticos binários. A ordem de precedência e as propriedades de associação de todos os operadores de D estão disponíveis no Tabela 2–11. Você pode controlar a precedência agrupando expressões entre parênteses ( ).

Operadores relacionais

D fornece os operadores relacionais binários, mostrados na tabela seguinte, a serem usados em seus programas. Todos esses operadores possuem o mesmo significado que em ANSI-C.

Tabela 2–7 Operadores relacionais de D

<

o operando esquerdo é menor que o operando direito 

<=

o operando esquerdo é menor ou igual ao operando direito 

>

o operando esquerdo é maior que o operador direito 

>=

o operando esquerdo é maior ou igual ao operando direito 

==

o operando esquerdo é igual ao operando direito 

!=

o operando esquerdo não é igual ao operando direito 

Os operadores relacionais são os mais usados para escrever predicados de D. Cada operador é avaliado com um valor de tipo int que é igual a um, se a condição for verdadeira, ou zero se for falsa.

Operadores relacionais podem ser aplicados a pares de inteiros, ponteiros ou seqüências. Se os ponteiros forem comparados, o resultado será equivalente a uma comparação de inteiros dos dois ponteiros interpretados como inteiros não assinados. Se as seqüências forem comparadas, o resultado será determinado como se estivesse sendo realizada uma strcmp(3C) nos dois operandos. Eis alguns exemplos de comparações de seqüências de D e seus resultados:

"café" < "expresso"

... retorna 1 (verdadeiro) 

"café" == "café"

... retorna 1 (verdadeiro) 

"café" >= "mocha"

... retorna 0 (falso) 

Operadores relacionais também podem ser usados para comparar um objeto de dados associado a um tipo de enumeração com qualquer uma das marcas de enumerador definidas pela enumeração. Enumerações são um recurso para criar constantes de inteiro nomeadas e são descritas em mais detalhes no Capítulo 8Definições de tipo e de constante.

Operadores lógicos

D fornece os seguintes operadores lógicos binários a serem usados em seus programas. Os dois primeiros operadores são equivalentes aos operadores ANSI-C correspondentes.

Tabela 2–8 Operadores lógicos de D

&&

AND lógico: verdadeiro se ambos os operandos forem verdadeiros

||

OR lógico: verdadeiro se um ou ambos os operandos forem verdadeiros

^^

XOR lógico: verdadeiro se exatamente um operando for verdadeiro

Os operadores lógicos são os mais usados para escrever predicados de D. O operador lógico AND realiza avaliação de circuito curto: Se o operando esquerdo for falso, a expressão direita não será avaliada. O operador lógico OR realiza avaliação de circuito curto: Se o operando esquerdo for verdadeiro, a expressão direita não será avaliada. O operador XOR lógico não realiza circuito curto: ambos os operandos da expressão são sempre avaliados.

Além dos operadores lógicos binários, o operador unário ! pode ser usado para realizar uma negação lógica de um único operando: converte um operando zero em um, e um operando diferente de zero em zero. Por convenção, os programadores de D usam ! quando trabalham com inteiros que representam valores booleanos, e == 0 quando trabalham com inteiros não booleanos, embora ambas as expressões tenham significado equivalente.

Os operadores lógicos podem ser aplicados a operandos de tipos de inteiro ou de ponteiro. Os operadores lógicos interpretam operandos de ponteiro como valores inteiros não assinados. Como em todos os operadores lógicos e relacionais em D, os operandos são verdadeiros caso possuam um valor inteiro diferente de zero e falsos caso possuam um valor inteiro igual a zero .

Operadores bit a bit

D fornece os seguintes operadores binários para manipular bits individuais dentro de operandos inteiros. Todos esses operadores possuem o mesmo significado em ANSI-C.

Tabela 2–9 Operadores bit a bit de D

&

AND bit a bit 

|

OR bit a bit 

^

XOR bit a bit 

<<

move o operando esquerdo para a esquerda pelo número de bits especificado pelo operando direito 

>>

move o operando esquerdo para a direita pelo número de bits especificado pelo operando direito 

O operador binário & é usado para limpar os bits de um operando inteiro. O operador binário | é usado para definir os bits em um operando inteiro. O operador binário ^ retorna um em cada posição de bit onde exatamente um dos bits de operando correspondente está definido.

Os operadores de deslocamento são usados para mover os bits para a esquerda ou para a direita em um determinado operando inteiro. O deslocamento para a esquerda preenche com zeros as posições de bit vazias no lado direito do resultado. O deslocamento para a direita usando um operando inteiro não assinado preenche com zeros as posições de bit vazias no lado esquerdo do resultado. O deslocamento para a direita usando um operando inteiro assinado preenche o lado esquerdo com o valor do bit de sinal, também conhecido como uma operação de deslocamento aritmético.

Mover um valor inteiro por um número negativo de bits ou por um número de bits maior que o número de bits no próprio operando esquerdo produz um resultado indefinido. O compilador de D produzirá uma mensagem de erro, caso detecte essa condição quando você compilar seu programa em D.

Além dos operadores lógicos binários, o operador unário ~ pode ser usado para realizar uma negação bit a bit de um único operando: ele converte cada bit zero no operando em um bit um, e cada bit um no operando em um bit zero.

Operadores de atribuição

D fornece os seguintes operadores de atribuição binários para modificar variáveis de D. Você só pode modificar variáveis e matrizes de D. Objetos de dados e constantes do kernel não podem ser modificados por meio de operadores de atribuição de D. O operador de atribuição possui o mesmo significado que em ANSI-C.

Tabela 2–10 Operadores de atribuição de D

=

define o operando esquerdo igual ao valor da expressão direita 

+=

incrementa o operando esquerdo pelo valor da expressão direita 

-=

decrementa o operando esquerdo pelo valor da expressão direita 

*=

multiplica o operando esquerdo pelo valor da expressão direita 

/=

divide o operando esquerdo pelo valor da expressão direita 

%=

modula o operando esquerdo pelo valor da expressão direita 

|=

OR bit a bit do operando esquerdo com o valor da expressão direita 

&=

AND bit a bit do operando esquerdo com o valor da expressão direita 

^=

XOR bit a bit do operando esquerdo com o valor da expressão direita 

<<=

move o operando esquerdo para a esquerda pelo número de bits especificado pelo valor da expressão direita 

>>=

move o operando esquerdo para a direita pelo número de bits especificado pelo valor da expressão direita 

Além do operador de distribuição =, os outros operadores de atribuição são fornecidos como abreviação para o uso do operador = com um dos outros operadores descritos anteriormente. Por exemplo, a expressão x = x + 1 é equivalente à expressão x += 1, exceto que a expressão x é avaliada uma vez. Estes operadores de atribuição obedecem às mesmas regras para tipos de operando que os formatos binários descritos anteriormente.

O resultado de qualquer operador de atribuição é uma expressão igual ao novo valor da expressão esquerda. Você pode usar os operadores de atribuição ou qualquer um dos operadores descritos até agora para formar expressões de complexidade arbitrária. Você pode usar parênteses ( ) para agrupar termos em expressões complexas.

Operadores de incremento e de decremento

D fornece os operadores unários especiais ++ e -- para incrementar e decrementar ponteiros e inteiros. Esses operadores possuem o mesmo significado que em ANSI-C. Esses operadores só podem ser aplicados a variáveis, e podem ser aplicados antes ou depois do nome da variável. Se o operador aparecer antes do nome da variável, a variável será modificada primeiro e a expressão resultante será igual ao novo valor da variável. Por exemplo, as duas expressões seguintes produzem resultados idênticos:

x += 1;

y = ++x;

y = x;

 

Se o operador aparecer depois do nome da variável, a variável será modificada depois que seu valor atual for retornado para ser usado na expressão. Por exemplo, as duas expressões seguintes produzem resultados idênticos:

y = x;

y = x--;

x -= 1;

 

Você pode usar os operadores de incremento e de decremento para criar novas variáveis sem declará-las. Se uma declaração de variável for omitida e o operador de incremento ou de decremento for aplicado a uma variável, a variável será declarada implicitamente como tipo int64_t.

Os operadores de incremento e de decremento podem ser aplicados às variáveis de inteiro ou ponteiro. Quando aplicados a variáveis de inteiro, os operadores incrementam ou decrementam o valor correspondente por um. Quando aplicados às variáveis de ponteiro, os operadores incrementam ou decrementam o endereço de ponteiro pelo tamanho do tipo de dados referenciado pelo ponteiro. Os ponteiros e a aritmética de ponteiro em D são discutidos no Capítulo 5Ponteiros e matrizes.

Expressões condicionais

Embora D não dê suporte a construções if-then-else, ela não oferece suporte a expressões condicionais simples que usam os operadores ? e : . Esses operadores permitem que três expressões sejam associadas, onde a primeira expressão é usada para avaliar condicionalmente uma das outras duas. Por exemplo, a declaração de D seguinte poderia ser usada para definir uma variável x como uma de duas seqüências, dependendo do valor de i:

x = i == 0 ? "zero" : "non-zero";

Neste exemplo, a expressão i == 0 é avaliada primeiro para determinar se é verdadeira ou falsa. Se a primeira expressão for verdadeira, a segunda expressão será avaliada e a expressão ?: retornará seu valor. Se a primeira expressão for falsa, a terceira expressão será avaliada e a expressão ?: retornará seu valor.

Como em qualquer operador de D, você pode usar vários operadores ?: em uma única expressão para criar mais expressões complexas. Por exemplo, a expressão seguinte tomaria uma variável char c contendo um dos caracteres 0-9, a-z ou A-Z, e retornaria o valor desse caractere quando interpretado como um dígito em um inteiro (base 16) hexadecimal:

hexval = (c >= '0' && c <= '9') ? c - '0' :
    (c >= 'a' && c <= 'z') ? c + 10 - 'a' : c + 10 - 'A';

A primeira expressão usada com ?: deve ser um ponteiro ou um inteiro para que seja avaliada em seu valor verdadeiro. A segunda e a terceira expressões podem ser de quaisquer tipos compatíveis. Você não pode construir uma expressão condicional onde, por exemplo, um caminho retorne uma seqüência e outro caminho retorne um inteiro. A segunda e a terceira expressões também não podem chamar uma função de rastreamento como trace() ou printf(). Se você quiser rastrear dados condicionalmente, use um predicado, como discutido no Capítulo 1Introdução.

Tipos de conversões

Quando as expressões são construídas por meio de operandos de tipos diferentes mas compatíveis, as conversões de tipo são realizadas para determinar o tipo da expressão resultante. As regras de D para conversões de tipo são as mesmas regras de conversão aritmética em ANSI-C. Essas regras às vezes são chamadas de conversões aritméticas usuais.

Uma forma simples de descrever as regras de conversão é a seguinte: cada tipo de inteiro é classificado na ordem char, short, int, long, long long, sendo que os tipos não assinados correspondentes recebem uma classificação acima de seu equivalente assinado, mas abaixo do próximo tipo inteiro. Quando você constrói uma expressão usando dois operandos inteiros, tais como x + y e os operandos são tipos de inteiros diferentes, o tipo de operando com a classificação mais alta é usado como o tipo de resultado.

Se for necessária uma conversão, o operando de classificação mais baixa é primeiro promovido para o tipo de classificação mais alto. A promoção não altera realmente o valor do operando: ela simplesmente estende o valor para um recipiente maior, de acordo com o seu sinal. Se um operando não assinado for promovido, os bits de ordem alta não utilizados do inteiro resultante serão preenchidos com zeros. Se um operando assinado for promovido, os bits de ordem alta não utilizados serão preenchidos por meio de extensão de sinal. Se um tipo assinado for convertido em um tipo não assinado, o tipo assinado primeiro tem o sinal estendido e, em seguida, é atribuído o novo tipo não assinado determinado pela conversão.

Inteiros e outros tipos também podem ser explicitamente convertidos de um tipo para outro. Em D, os ponteiros e os inteiros podem ser convertidos em quaisquer tipos de inteiro ou de ponteiro, mas não para outros tipos. As regras para conversão e promoção de seqüências e matrizes de caracteres são discutidas no Capítulo 6Seqüências. Uma conversão de inteiro ou ponteiro é formado por meio de uma expressão tal como:

y = (int)x;

onde o tipo de destino é colocado entre parênteses e usado para prefixar a expressão de origem. Inteiros são convertidos em tipos de classificação superior por meio de promoção. Inteiros são convertidos em tipos de classificação quando se zera o excesso de bits de ordem alta do inteiro.

Como D não permite a aritmética de ponto flutuante, nenhuma conversão de operando de ponto flutuante é permitida e nenhuma regra para conversão de ponto flutuante implícita é definida.

Precedência

As regras de D para precedência de operador e associação são descritas na tabela seguinte. Essas regras são algo complexas, mas são necessárias para fornecer compatibilidade precisa com as regras de precedência de operador ANSI-C. As entradas da tabela estão na ordem da precedência mais alta para a precedência mais baixa.

Tabela 2–11 Precedência e associação de operador de D

Operadores 

Associação 

() [] -> .

esquerda para direita 

! ~ ++ -- + - * & (tipo) sizeof stringof offsetof xlate

direita para esquerda 

* / %

esquerda para direita 

+ -

esquerda para direita 

<< >>

esquerda para direita 

< <= > >=

esquerda para direita 

== !=

esquerda para direita 

&

esquerda para direita 

^

esquerda para direita 

|

esquerda para direita 

&&

esquerda para direita 

^^

esquerda para direita 

||

esquerda para direita 

?:

direita para esquerda 

= += -= *= /= %= &= ^= |= <<= >>=

direita para esquerda 

,

esquerda para direita 

Existem vários operadores na tabela sobre os quais ainda não discutimos; eles serão abordados nos próximos capítulos:

sizeof

Calcula o tamanho de um objeto (Capítulo 7Structs e uniões)

offsetof

Calcula o deslocamento de um membro de tipo (Capítulo 7Structs e uniões)

stringof

Converte o operando em uma seqüência (Capítulo 6Seqüências)

xlate

Traduz um tipo de dados (Capítulo 40Tradutores)

unary &

Calcula o endereço de um objeto (Capítulo 5Ponteiros e matrizes)

* unário

Cancela a referência de um ponteiro a um objeto (Capítulo 5Ponteiros e matrizes)

-> e .

Acessa um membro de uma estrutura ou tipo de união (Capítulo 7Structs e uniões)

O operador vírgula (,) listado na tabela é para compatibilidade com o operador de vírgula ANSI-C, que pode ser usado para avaliar um conjunto de expressões na ordem da esquerda para direita e retornar o valor da expressão da extrema direita. Este operador é fornecido estritamente para compatibilidade com C e geralmente não deve ser usado.

A entrada (), na tabela de precedência de operador, representa uma chamada a uma função. Exemplos de chamadas a funções como printf() e trace() são apresentados no Capítulo 1Introdução. Uma vírgula também é usada em D para listar argumentos de funções e para formar listas de chaves de matriz associativa. Essa vírgula não é a mesma que o operador vírgula e não garante a avaliação da esquerda para a direita. O compilador de D não garante a ordem de avaliação de argumentos de uma função ou das chaves de uma matriz associativa. Você deve ter cuidado ao usar expressões com efeitos colaterais interativos, tal como o par de expressões i e i++, nestes contextos.

A entrada [] na tabela de precedência de operador representa uma matriz ou referência de matriz associativa. Exemplos de matriz associativa são apresentados no Capítulo 1Introdução. Um tipo especial de matriz associativa chamada agregação é descrito no Capítulo 9Agregações. O operador [] também pode ser usado para indexar matrizes C de tamanho fixo, como descrito no Capítulo 5Ponteiros e matrizes.